package cc.rengu.igas.momp.core.service.trans;

import cc.rengu.igas.momp.common.constant.CommonConstant;
import cc.rengu.igas.momp.common.dao.*;
import cc.rengu.igas.momp.common.dao.impl.*;
import cc.rengu.igas.momp.common.entity.*;
import cc.rengu.igas.momp.common.enums.*;
import cc.rengu.igas.momp.common.util.MompDateUtil;
import cc.rengu.igas.momp.core.model.TransactionResource;
import cc.rengu.igas.momp.core.realize.TransactionResourceService;
import cc.rengu.igas.momp.core.realize.impl.TransactionResourceServiceImpl;
import cc.rengu.igas.momp.facade.bean.PaymentOrderInfoBean;
import cc.rengu.igas.momp.facade.bean.PrePaymentAvailableCouponMcInfoBean;
import cc.rengu.igas.momp.facade.bean.PrePaymentAvailableMoneyOffMcInfoBean;
import cc.rengu.igas.momp.facade.bean.UserMcInfoBean;
import cc.rengu.igas.momp.facade.request.QueryAvailableDiscountInfoBeforePaymentRequest;
import cc.rengu.igas.momp.facade.response.QueryAvailableDiscountInfoBeforePaymentResponse;
import cc.rengu.jradp.mods.dbs.Database;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.AppConfigConstant;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.entity.BinInfo;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.realize.BinInfoService;
import cc.rengu.oltp.service.realize.impl.BinInfoServiceImpl;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.base.StringUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 支付前可优惠信息查询接口实现
 *
 * @author Jinan Liu
 * @version 1.0.0
 * @since 2020/4/2 17:48
 */
public class PrePaymentAvailableDiscountInfoQueryService extends RadpService {

    /**
     * 法人机构号
     */
    private String globalInstId;
    /**
     * 渠道交易日期
     */
    private String globalTxnDate;
    /**
     * 渠道交易时间
     */
    private String globalTxnTime;
    /**
     * 用户ID
     */
    private String globalUserId;
    /**
     * 原系统标识
     */
    private String globalsSrcSysId;
    /**
     * 流水号
     */
    private String globalTraceNo;
    /**
     * 当前交易系统时间戳
     */
    private String globalTimeStamp;
    /**
     * 商户基本信息列表
     */
    private List<TBMchntBaseInfo> tbMchntBaseInfoList;
    /**
     * 交易控制实体类
     */
    private TransactionResource transactionResource;
    /**
     * 业务操作流水表数据库操作实体类
     */
    List<TMTxnBizOp> tmTxnBizOpList;
    private BigDecimal zero = BigDecimal.ZERO;

    /**
     * 对客营销活动用户统计表是否需要累加昨天数据
     */
    private int batchStatusStat = CommonConstant.FLAG_NOT_SET;
    /**
     * 对客营销活动用户月统计表是否需要累加昨天数据
     */
    private int batchStatusStatMonth = CommonConstant.FLAG_NOT_SET;
    /**
     * 优惠id
     */
    private String discountId;

    @Override
    protected int bizInit(String s) {
        return CommonConstant.PROCESS_SUCCESS;
    }

    @Override
    protected int bizProcess(String s, int i) {

        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();

        try {

            QueryAvailableDiscountInfoBeforePaymentRequest queryAvailableDiscountInfoBeforePaymentRequest = new QueryAvailableDiscountInfoBeforePaymentRequest();
            ConvertUtil.convertOutput(queryAvailableDiscountInfoBeforePaymentRequest);

            QueryAvailableDiscountInfoBeforePaymentResponse queryAvailableDiscountInfoBeforePaymentResponse = new QueryAvailableDiscountInfoBeforePaymentResponse();
            queryAvailableDiscountInfoBeforePaymentResponse.setHeader(queryAvailableDiscountInfoBeforePaymentRequest.getHeader());
            BizResponse<QueryAvailableDiscountInfoBeforePaymentResponse> bizResponse = new BizResponse<>();
            bizResponse.setResult(queryAvailableDiscountInfoBeforePaymentResponse);

            /* 报文检查及全局变量赋值 */
            messageValidation(queryAvailableDiscountInfoBeforePaymentRequest);

            /* 服务调用 */
            BizResponse<QueryAvailableDiscountInfoBeforePaymentResponse> bizResponseNew = queryAvailableDiscountInfoBeforePayment(xmlTreeUtil, queryAvailableDiscountInfoBeforePaymentRequest, queryAvailableDiscountInfoBeforePaymentResponse);

            ConvertUtil.convertInput(bizResponseNew.getResult());

        } catch (BizException e) {
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, e.getCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, e.getMessage());
            } catch (Exception e1) {
                rglog.error(StringUtil.ExceptionToString(e1));
            }
        } catch (Exception e) {
            rglog.error(StringUtil.ExceptionToString(e));
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespDesc());
            } catch (Exception e1) {
                rglog.error(StringUtil.ExceptionToString(e1));
            }
        }

        return CommonConstant.PROCESS_SUCCESS;
    }

    @Override
    protected int bizTerminate(String s) {
        return CommonConstant.PROCESS_SUCCESS;
    }

    /**
     * 支付前对客类可优惠信息查询
     *
     * @param xmlTreeUtil                                     内部XML树
     * @param queryAvailableDiscountInfoBeforePaymentRequest  支付前可优惠信息查询接口请求对象
     * @param queryAvailableDiscountInfoBeforePaymentResponse 支付前可优惠信息查询接口应答对象
     * @return cc.rengu.oltp.service.model.BizResponse<cc.rengu.igas.momp.facade.response.QueryAvailableDiscountInfoBeforePaymentResponse> 支付前可优惠信息查询接口应答对象
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/6/2 19:22
     */
    private BizResponse<QueryAvailableDiscountInfoBeforePaymentResponse> queryAvailableDiscountInfoBeforePayment(XmlTreeUtil xmlTreeUtil, QueryAvailableDiscountInfoBeforePaymentRequest queryAvailableDiscountInfoBeforePaymentRequest, QueryAvailableDiscountInfoBeforePaymentResponse queryAvailableDiscountInfoBeforePaymentResponse) throws Exception {

        BizResponse<QueryAvailableDiscountInfoBeforePaymentResponse> bizResponse = new BizResponse<>();
        /* 查询订单中所有商户对应的商户基本信息 */
        tbMchntBaseInfoList = new ArrayList<>();
        MchntInfoMapper mchntInfoMapper = new MchntInfoMapperImpl();
        for (PaymentOrderInfoBean paymentOrderInfoBean : queryAvailableDiscountInfoBeforePaymentRequest.getOrderDetailList()) {

            // 检查上传字段 不能为负数
            checkOrderDetFieldHasNegativeNumber(paymentOrderInfoBean);

            /* 根据商户编号查询商圈编号 */
            String mchntNo = paymentOrderInfoBean.getMchntNo();
            if (!StringUtil.isNullorEmpty(mchntNo)) {
                /* 查询商户基本信息表 */
                TBMchntBaseInfo tbMchntBaseInfo = mchntInfoMapper.selectMompMchntBaseInfoByPrimaryKey(globalInstId, mchntNo);
                if (null == tbMchntBaseInfo) {
                    rglog.error("查询法人机构<{}>商户<{}>基本信息失败!", globalInstId, mchntNo);
                    throw new BizException(RespCodeEnum.NO_TRANS_RECORD.getRespCode(), RespCodeEnum.NO_TRANS_RECORD.getRespDesc());
                } else {
                    tbMchntBaseInfoList.add(tbMchntBaseInfo);
                }
            } else {
                rglog.error("需要上送商户编号!");
                throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
        }

        /* 抢占减免类活动数据计算资源池，若资源已满或占用失败,则不处理减免类数据,否则处理减免类数据 */
        TransactionResourceService transactionResourceService = new TransactionResourceServiceImpl();
        transactionResourceService.pushSingleRecordToResourcePool(transactionResource);
        List<UserMcInfoBean> userMcInfoBeanList = new ArrayList<>();
        //上送的userId为list  循环取每个userId对应的优惠信息
        for (int i = 0; i < queryAvailableDiscountInfoBeforePaymentRequest.getUserInfoBean().getUserIdList().size(); i++) {
            globalUserId = queryAvailableDiscountInfoBeforePaymentRequest.getUserInfoBean().getUserIdList().get(i);
            UserMcInfoBean userMcInfoBean = new UserMcInfoBean();
            userMcInfoBean.setUserId(globalUserId);

            try {
                /* 查询合并支付订单中可用减免活动信息 */
                List<PrePaymentAvailableMoneyOffMcInfoBean> prePaymentAvailableMoneyOffMcInfoBeanList = processMoneyOffProcedure(queryAvailableDiscountInfoBeforePaymentRequest.getOrderDetailList());
                if (null == prePaymentAvailableMoneyOffMcInfoBeanList || prePaymentAvailableMoneyOffMcInfoBeanList.isEmpty()) {
                    rglog.info("机构<{}>的用户<{}>未查询到可用的减免信息!", globalInstId, globalUserId);
                } else {
                    prePaymentAvailableMoneyOffMcInfoBeanList = prePaymentAvailableMoneyOffMcInfoBeanList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(PrePaymentAvailableMoneyOffMcInfoBean::getMcNo))), ArrayList::new));
                    Comparator<PrePaymentAvailableMoneyOffMcInfoBean> discountLimit = Comparator.comparingDouble((PrePaymentAvailableMoneyOffMcInfoBean prePaymentAvailableMoneyOffMcInfoBean) -> Double.parseDouble(prePaymentAvailableMoneyOffMcInfoBean.getDiscountAmt())).reversed();
                    prePaymentAvailableMoneyOffMcInfoBeanList.sort(discountLimit);
                    userMcInfoBean.setMoneyOffInfoList(prePaymentAvailableMoneyOffMcInfoBeanList);

                    prePaymentAvailableMoneyOffMcInfoBeanList.forEach(item -> createMoneyOffOprLog(item));
                }

            } catch (BizException e) {
                rglog.info("异常信息: <{}>", StringUtil.ExceptionToString(e));

            } catch (Exception e) {
                rglog.info("异常信息: <{}>", StringUtil.ExceptionToString(e));
                throw e;
            }

            /* 查询合并支付订单中可用卡券信息 */
            List<PrePaymentAvailableCouponMcInfoBean> prePaymentAvailableCouponMcInfoBeanList = processCouponProcedure(queryAvailableDiscountInfoBeforePaymentRequest.getOrderDetailList());
            if (null == prePaymentAvailableCouponMcInfoBeanList || prePaymentAvailableCouponMcInfoBeanList.isEmpty()) {
                /* 未查询到合并支付订单可用卡券信息 */
                rglog.info("机构<{}>的用户<{}>未查询到可用的卡券信息!", globalInstId, globalUserId);
            } else {
                Comparator<PrePaymentAvailableCouponMcInfoBean> couponAmt = Comparator.comparingDouble((PrePaymentAvailableCouponMcInfoBean prePaymentAvailableCouponMcInfoBean) -> Double.parseDouble(prePaymentAvailableCouponMcInfoBean.getCouponAmt())).reversed();
                prePaymentAvailableCouponMcInfoBeanList.sort(couponAmt);
                userMcInfoBean.setCouponInfoList(prePaymentAvailableCouponMcInfoBeanList);
            }
            userMcInfoBeanList.add(userMcInfoBean);
        }
        queryAvailableDiscountInfoBeforePaymentResponse.setUserMcInfoBeanList(userMcInfoBeanList);
        queryAvailableDiscountInfoBeforePaymentResponse.setUserType(queryAvailableDiscountInfoBeforePaymentRequest.getUserInfoBean().getUserType());


        /* 登记业务操作流水表数据-曝光人数和曝光次数使用 */
        if (tmTxnBizOpList.isEmpty()) {
            /* 无业务数据待登记 */
            rglog.info("无业务流水数据待登记!");
        } else {
            //去重相同活动号的流水表信息
            tmTxnBizOpList = tmTxnBizOpList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TMTxnBizOp::getMcNo))), ArrayList::new));

            /* 开启数据库事务 */
            String dbPoolName = XmlConfigUtil.getXmlConfigCacheKeyValue(AppConfigConstant.DATABASE_CONF_NODE, AppConfigConstant.MOMP_POOL_NAME);
            String corporation = xmlTreeUtil.getXmlTreeStringValue(AppParamConstant.CORPORATION);
            if (null != corporation && !corporation.isEmpty()) {
                String dbPoolCashNode = corporation.trim() + AppParamConstant.DATABASE_CONF_NODE;
                dbPoolName = XmlConfigUtil.getXmlConfigCacheKeyValue(dbPoolCashNode, AppConfigConstant.MOMP_POOL_NAME);
            }
            DbsUtil dbsUtil = new DbsUtil(dbPoolName);
            dbsUtil.dbsBeginTransaction();

            try {

                TMTxnBizOpMapper tmTxnBizOpMapper = new TMTxnBizOpMapperImpl();
                int returnCode = tmTxnBizOpMapper.insertTmTxnBizOpList(tmTxnBizOpList);
                if (Database.DBS_SUCCESS != returnCode) {
                    dbsUtil.dbsEndTransaction(false);
                } else {
                    dbsUtil.dbsEndTransaction(true);
                }

            } catch (Exception e) {
                rglog.error("登记业务流水数据失败! <{}>", StringUtil.ExceptionToString(e));
                dbsUtil.dbsEndTransaction(false);
            }
        }

        try {

            /* 从资源池将本笔交易占用的资源释放 */
            transactionResourceService.popSingleRecordFromResourcePool(transactionResource);

        } catch (BizException e) {
            rglog.info("异常信息: <{}>", StringUtil.ExceptionToString(e));

        } catch (Exception e) {
            rglog.info("异常信息: <{}>", StringUtil.ExceptionToString(e));
            throw e;
        }

        bizResponse.setRspSysId(ChannelEnum.MOMP.getChannelType());
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());

        queryAvailableDiscountInfoBeforePaymentResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        queryAvailableDiscountInfoBeforePaymentResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setResult(queryAvailableDiscountInfoBeforePaymentResponse);

        return bizResponse;
    }


    /**
     * 查询用户可用卡券信息
     *
     * @param paymentOrderInfoBeanList 订单明细对象列表
     * @return java.util.List<cc.rengu.igas.momp.facade.bean.PrePaymentAvailableCouponMcInfoBean> 卡券类优惠信息对象
     * @author Jinan Liu
     * @since 2020/4/27 21:37
     */
    private List<PrePaymentAvailableCouponMcInfoBean> processCouponProcedure(List<PaymentOrderInfoBean> paymentOrderInfoBeanList) {

        try {
            rglog.info("开始查询卡券类营销活动信息.....");
            /* 查询用户绑定卡券信息 */
            List<TMCouponInfo> tmCouponInfoList = selectUserCouponBoundListInfo(globalInstId, globalUserId, globalTxnDate);
            if (null == tmCouponInfoList || tmCouponInfoList.isEmpty()) {
                /* 用户无已领取卡券需要处理 */
                rglog.info("机构<{}>的用户<{}>无已领取卡券需要处理", globalInstId, globalUserId);
                return null;
            }

            List<TMCouponInfo> filteredCouponList = filterateCouponViaOrderAmt(tmCouponInfoList, paymentOrderInfoBeanList);
            if (filteredCouponList.isEmpty()) {
                /* 用户卡券面额全部大于最大订单金额,不可在当前订单使用 */
                rglog.info("机构<{}>的用户<{}>无满足条件的可用卡券", globalInstId, globalUserId);
                return null;
            }

            List<TMCouponInfo> filteredCouponList1 = new ArrayList<>();

            /* 查询每个卡券对应的营销活动信息 */
            for (TMCouponInfo tmCouponInfo : filteredCouponList) {

                /* 判断每个营销活动都有哪些商户可用 */
                TMCouponInfo tmCouponInfo1 = checkCouponValidation(tmCouponInfo, paymentOrderInfoBeanList);
                if (null != tmCouponInfo1) {
                    //活动门槛 criteria
                    BigDecimal criteria = new BigDecimal(tmCouponInfo1.getCriteria()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                    //卡券可抵扣金额  couponAmt
                    BigDecimal couponAmt = new BigDecimal(tmCouponInfo1.getCouponAmt()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

                    if (CommonConstant.ZERO < criteria.compareTo(couponAmt)) {
                        filteredCouponList1.add(tmCouponInfo1);
                    }
                }
            }

            /* 未找到满足参与营销活动的卡券信息 */
            if (filteredCouponList1.isEmpty()) {
                return null;
            } else {
                return filteredCouponList1.stream().map(this::convertCouponInfo).collect(Collectors.toList());
            }

        } catch (Exception e) {
            rglog.error(StringUtil.ExceptionToString(e));
            throw new BizException(RespCodeEnum.SYSTEM_ERROR.getRespCode(), RespCodeEnum.SYSTEM_ERROR.getRespDesc());
        }
    }


    /**
     * 查询商户及用户可用卡券信息
     *
     * @param paymentOrderInfoBeanList 订单明细对象列表
     * @return java.util.List<cc.rengu.igas.momp.facade.bean.PrePaymentAvailableMoneyOffMcInfoBean> 减免类优惠信息对象
     * @author Jinan Liu
     * @since 2020/4/27 21:50
     */
    private List<PrePaymentAvailableMoneyOffMcInfoBean> processMoneyOffProcedure(List<PaymentOrderInfoBean> paymentOrderInfoBeanList) {

        List<PrePaymentAvailableMoneyOffMcInfoBean> prePaymentAvailableMoneyOffMcInfoBeanList = new ArrayList<>();
        rglog.info("开始查询减免类营销活动信息.....");
        try {

            /* 每个子订单均需判断一遍是否有可用营销活动 */
            for (PaymentOrderInfoBean paymentOrderInfoBean : paymentOrderInfoBeanList) {

                String mchntNo = paymentOrderInfoBean.getMchntNo();
                String selefOrChainMchntNo = paymentOrderInfoBean.getMchntNo();

                TBMchntBaseInfo tbMchntBaseInfo = tbMchntBaseInfoList.stream().filter(object -> object.getMchntNo().equals(mchntNo)).collect(Collectors.toList()).get(CommonConstant.ZERO);
                if (null != tbMchntBaseInfo) {
                    /* 使用商户编号匹配减免类营销活动信息 */
                    List<TMMcMchntInfo> tmMcMchntInfoList;
                    //判断商户类型，如果是连锁门店商户，非独立清算的商户需要用上级的商户查询营销活动
                    //商户性质
                    String mchntType = tbMchntBaseInfo.getMchntType();
                    //连锁商户号
                    String chainMchntNo = tbMchntBaseInfo.getChainMchntNo();
                    //是否独立维护商户资料
                    String independentDataFlag = tbMchntBaseInfo.getIndependentDataFlag();
                    //如果是非独立清算的，需要用上级的商户查询；独立清算的暂不处理，用自己的查询
                    if ((CommonConstant.NO.equals(independentDataFlag) && MchntTypeEnum.CHAIN_MCHNT_STORE.getMchntType().equals(mchntType))) {
                        rglog.info("商户<{}> 商户类型为11:连锁商户门店，是否独立维护商户资料<{}> 非独立清算商户,获取营销活动时需根据上级商户<{}> 获取!", mchntNo, independentDataFlag, chainMchntNo);
                        //查询上级商户的基本信息
                        MchntInfoMapper mchntInfoMapper = new MchntInfoMapperImpl();
                        TBMchntBaseInfo chainMchntBaseInfo = mchntInfoMapper.selectMompMchntBaseInfoByPrimaryKey(globalInstId, chainMchntNo);
                        if (null == chainMchntBaseInfo) {
                            //查询不到商户信息，流程结束
                            rglog.error("查询当前商户<{}>的上级商户<{}>基本信息信息失败!", mchntNo, chainMchntNo);
                            continue;
                        }
                        tmMcMchntInfoList = matchMcMchntInfoByUsingMchntInfo(chainMchntBaseInfo);
                        selefOrChainMchntNo = chainMchntBaseInfo.getMchntNo();
                    } else {
                        rglog.info("商户<{}> 是否独立维护商户资料<{}> 商户类型为<{}> 普通商户或独立清算商户，均使用当前商户号查询营销信息！", mchntNo, independentDataFlag, mchntType);
                        /* 使用商户编号匹配减免类营销活动信息 */
                        tmMcMchntInfoList = matchMcMchntInfoByUsingMchntInfo(tbMchntBaseInfo);
                    }

                    if (null == tmMcMchntInfoList || tmMcMchntInfoList.isEmpty()) {
                        rglog.info("使用商户号MCHNT_NO=<{}>或商户所属商圈编号均未找到对应匹配的营销活动信息! INST_ID=<{}>", selefOrChainMchntNo, globalInstId);
                        continue;
                    }

                    /* 若商户列表中存在数据,则每个列表中的对象都单独计算,取额度限制比较前优惠力度最高的营销活动进行优惠 */
                    McMoneyOffTxnData mcMoneyOffTxnData = convertMoneyOffInfoData(paymentOrderInfoBean);

                    /* 取营销活动基本信息 */
                    List<TMMcMoneyOffInfo> tmMcMoneyOffInfoList = new ArrayList<>();
                    tmMcMchntInfoList.forEach(item -> getMoneyOffMcInfo(item, tmMcMoneyOffInfoList));
                    if (tmMcMoneyOffInfoList.isEmpty()) {
                        rglog.error("未获取到营销活动信息!");
                        continue;
                    }

                    /* 逐个营销活动进行处理 */
                    for (TMMcMoneyOffInfo tmMcMoneyOffInfo : tmMcMoneyOffInfoList) {

                        /* 单个营销活动处理失败不做进一步处理,流程继续 */
                        String mcNo = tmMcMoneyOffInfo.getMcNo();
                        String mcType = tmMcMoneyOffInfo.getMcType();

                        /* 检查营销活动状态 */
                        int retCode = checkMcStatus(tmMcMoneyOffInfo, selefOrChainMchntNo);
                        if (CommonConstant.PROCESS_SUCCESS != retCode) {
                            rglog.error("机构<{}>的减免类营销活动<{}>信息校验失败! RETURN_CODE=<{}>", tmMcMoneyOffInfo.getInstId(), tmMcMoneyOffInfo.getMcNo(), retCode);
                            continue;
                        }

                        /* 判断是否在营销活动允许的时间范围内-无需记录对应的时间规则 */
                        if (CommonConstant.ALL_TIME_SUPPORT.equals(tmMcMoneyOffInfo.getMcTimeFlag())) {
                            rglog.info("机构<{}>的营销活动<{}>在任意时间段内可用!", globalInstId, mcNo);
                        } else if (CommonConstant.SPECIFIC_TIME_SUPPORT.equals(tmMcMoneyOffInfo.getMcTimeFlag())) {
                            rglog.info("机构<{}>的营销活动<{}>在指定时间段内可用,需要进一步判断当前时间!", globalInstId, mcNo);
                            List<TMMcTimeInfo> tmMcTimeInfoList = getAllMcTimeListInfo(globalInstId, mcNo);
                            if (null == tmMcTimeInfoList || tmMcTimeInfoList.isEmpty()) {
                                rglog.info("获取机构<{}>的营销活动<{}>时间规则信息失败,本营销活动不予优惠!", globalInstId, mcNo);
                                continue;
                            } else {
                                retCode = checkMcTimeInfo(mcMoneyOffTxnData.getTransDate(), mcMoneyOffTxnData.getTransTime(), tmMcTimeInfoList);
                                if (CommonConstant.PROCESS_SUCCESS != retCode) {
                                    rglog.info("获取机构<{}>的营销活动<{}>时间规则信息匹配失败,本营销活动不予优惠!", globalInstId, mcNo);
                                    continue;
                                } else {
                                    rglog.info("获取机构<{}>的营销活动<{}>时间规则信息匹配成功,本营销活动可以优惠!", globalInstId, mcNo);
                                }
                            }
                        } else {
                            rglog.error("机构<{}>的营销活动<{}>活动时间标志<{}>异常,本营销活动不予优惠!", globalInstId, mcNo, tmMcMoneyOffInfo.getMcTimeFlag());
                            continue;
                        }
                        //查询该用户，活动下的营销用户信息表信息
                        List<TMMcUserInfo> userInfoList = checkUserInfo(globalInstId, mcNo, mcMoneyOffTxnData.getUserId());
                        //测试账户
                        List<TMMcUserInfo> testUserInfoList = new ArrayList<>();
                        //正式账户
                        List<TMMcUserInfo> formalUserInfoList = new ArrayList<>();
                        if (null != userInfoList && userInfoList.size() > 0) {
                            testUserInfoList = userInfoList.stream().filter(item -> item.getAcctFlag().equals(CommonConstant.ACCT_FLAG_TESTING)).collect(Collectors.toList());
                            formalUserInfoList = userInfoList.stream().filter(item -> item.getAcctFlag().equals(CommonConstant.ACCT_FLAG_NORMAL)).collect(Collectors.toList());
                        }
                        /* 判断用户是否在营销活动允许的用户范围内-无需记录对应的用户规则 */
                        if (CommonConstant.ALL_CLIENT_SUPPORT.equals(tmMcMoneyOffInfo.getClientRange())) {
                            rglog.info("机构<{}>的营销活动<{}>支持对所有用户减免,继续校验后续信息!", globalInstId, mcNo);
                            if (tmMcMoneyOffInfo.getMcStatus().equals(McStatusEnum.TESTING.getMcStatusCode()) && testUserInfoList.isEmpty()) {
                                rglog.info("获取机构<{}>的营销活动<{}>用户规则信息匹配失败,本营销活动不予优惠!", globalInstId, mcNo);
                                continue;
                            }
                            //判断用户参与活动次数是否超过活动配置的限制次数——不限定用户
                            Boolean userAttendIsReachLimit = checkIsUserReachLimit(tmMcMoneyOffInfo, null);
                            if (!userAttendIsReachLimit) {
                                rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数大于等于最大限制，卡券无法使用！", globalUserId, mcNo);
                                continue;
                            }

                        } else if (CommonConstant.SPECIFIC_CLIENT_SUPPORT.equals(tmMcMoneyOffInfo.getClientRange())) {
                            rglog.info("机构<{}>的营销活动<{}>支持对部分用户减免,需要进一步判断当前用!", globalInstId, mcNo);
                            ;
                            if (formalUserInfoList.size() > 0 && tmMcMoneyOffInfo.getMcStatus().equals(McStatusEnum.PROGRESSING.getMcStatusCode())) {
                                rglog.info("获取机构<{}>的营销活动<{}>用户规则信息匹配成功,继续校验后续信息!", globalInstId, mcNo);

                                //判断用户参与活动次数是否超过活动配置的限制次数——正式用户
                                Boolean userAttendIsReachLimit = checkIsUserReachLimit(tmMcMoneyOffInfo, formalUserInfoList);
                                if (!userAttendIsReachLimit) {
                                    rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数大于等于最大限制，卡券无法使用！", globalUserId, mcNo);
                                    continue;
                                }

                            } else if (testUserInfoList.size() > 0 && tmMcMoneyOffInfo.getMcStatus().equals(McStatusEnum.TESTING.getMcStatusCode())) {
                                rglog.info("获取机构<{}>的营销活动<{}>用户规则信息匹配成功,继续校验后续信息!", globalInstId, mcNo);

                                //判断用户参与活动次数是否超过活动配置的限制次数——测试用户
                                Boolean userAttendIsReachLimit = checkIsUserReachLimit(tmMcMoneyOffInfo, testUserInfoList);
                                if (!userAttendIsReachLimit) {
                                    rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数大于等于最大限制，卡券无法使用！", globalUserId, mcNo);
                                    continue;
                                }
                            } else {
                                rglog.info("获取机构<{}>的营销活动<{}>用户规则信息匹配失败,本营销活动不予优惠!", globalInstId, mcNo);
                                continue;
                            }
                        } else {
                            rglog.error("机构<{}>的营销活动<{}>客户范围<{}>异常,本营销活动不予优惠!", globalInstId, mcNo, tmMcMoneyOffInfo.getClientRange());
                            continue;
                        }
                        /* 取营销活动规则 */
                        List<TMMcMoneyOffRuleInfo> tmMcMoneyOffRuleInfoList = selectMoneyOffRuleInfoList(globalInstId, mcNo);
                        if (null == tmMcMoneyOffRuleInfoList) {
                            /* 未取到营销活动规则信息,本营销活动不可以优惠! */
                            rglog.info("获取机构<{}>的营销活动<{}>减免规则信息匹配失败,本营销活动不予优惠!", globalInstId, mcNo);
                            continue;
                        }

                        /* 取符合条件的优惠最高的档次判断是否可以优惠 */
                        TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo;
                        BigDecimal orderAmt = new BigDecimal(mcMoneyOffTxnData.getOrderAmt()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                        rglog.debug("ORDER_AMT=<{}>", orderAmt.toString());

                        List<TMMcMoneyOffRuleInfo> tmMcMoneyOffRuleInfoList1 = new ArrayList<>();
                        for (TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo1 : tmMcMoneyOffRuleInfoList) {
                            BigDecimal criteriaAmt = new BigDecimal(tmMcMoneyOffRuleInfo1.getCriteria()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                            if (CommonConstant.ZERO >= criteriaAmt.compareTo(orderAmt)) {
                                tmMcMoneyOffRuleInfoList1.add(tmMcMoneyOffRuleInfo1);
                            }
                        }
                        if (tmMcMoneyOffRuleInfoList1.isEmpty()) {
                            rglog.info("订单金额<{}>不满足法人机构<{}>的减免类营销活动<{}>的任意一档规则,本营销活动不予优惠!", mcMoneyOffTxnData.getOrderAmt(), globalInstId, mcNo);
                            continue;
                        } else {
                            tmMcMoneyOffRuleInfo = tmMcMoneyOffRuleInfoList1.stream().max(Comparator.comparing(TMMcMoneyOffRuleInfo::getRuleIndex)).get();
                            rglog.info("订单金额<{}>满足法人机构<{}>的减免类营销活动<{}>的第<{}>档规则,继续校验后续信息!", mcMoneyOffTxnData.getOrderAmt(), globalInstId, mcNo, tmMcMoneyOffRuleInfo.getRuleIndex());
                        }

                        MoneyOffAmountData moneyOffAmountData = new MoneyOffAmountData();
                        moneyOffAmountData.setMchntNo(selefOrChainMchntNo);
                        moneyOffAmountData.setMcStartDate(tmMcMoneyOffInfo.getMcStartDate());
                        moneyOffAmountData.setSponsor(tmMcMoneyOffInfo.getSponsor());
                        copyMoneyOffRuleInfoAmountData(tmMcMoneyOffRuleInfo, moneyOffAmountData);

                        /* 根据营销活动类型计算营销活动补贴-规则上包下不包 */
                        String subsidy = calculateMcDiscountAmount(mcMoneyOffTxnData, mcType, tmMcMoneyOffRuleInfo);
                        moneyOffAmountData.setFloorAmt(mcMoneyOffTxnData.getFloorAmt());
                        moneyOffAmountData.setCellingAmt(mcMoneyOffTxnData.getCellingAmt());
                        if (null == subsidy) {
                            rglog.info("机构<{}>的营销活动<{}>减免金额计算失败,本营销活动不予优惠!", globalInstId, mcNo);
                            continue;
                        } else {
                            moneyOffAmountData.setTotalSubsidy(subsidy);
                        }
                        rglog.debug("TOTAL_SUBSIDY=<{}>", subsidy);

                        McSubsidyData mcSubsidyData = new McSubsidyData();
                        mcSubsidyData.setTotalSubsidy(subsidy);
                        mcSubsidyData.setSponsor(tmMcMoneyOffInfo.getSponsor());
                        if (CommonConstant.SPONSOR_MIXED.equals(tmMcMoneyOffInfo.getSponsor())) {
                            mcSubsidyData.setBudget(tmMcMoneyOffInfo.getBudget());
                            mcSubsidyData.setBankBudget(tmMcMoneyOffInfo.getBankBudget());
                            mcSubsidyData.setExpectMchntQty(tmMcMoneyOffInfo.getExpectMchntQty());
                            mcSubsidyData.setBankBudgetRatio(tmMcMoneyOffInfo.getBankBudgetRatio());
                        }
                        mcSubsidyData.setMcType(mcType);

                        /* 计算银行和商户出资比例 */
                        retCode = calculateBankAndMchntSubsidyRatio(mcSubsidyData);
                        if (CommonConstant.PROCESS_FAILED == retCode) {
                            rglog.info("机构<{}>的营销活动<{}>计算银行补贴金额和商户补贴金额失败,本营销活动不予优惠!", globalInstId, mcNo);
                            continue;
                        }

                        rglog.debug("TOTAL_SUBSIDY=<{}>, BANK_SUBSIDY=<{}>, MCHNT_SUBSIDY=<{}>", mcSubsidyData.getTotalSubsidy(), mcSubsidyData.getBankSubsidy(), mcSubsidyData.getMchntSubsidy());

                        moneyOffAmountData.setBankSubsidy(mcSubsidyData.getBankSubsidy());
                        moneyOffAmountData.setMchntSubsidy(mcSubsidyData.getMchntSubsidy());
                        if (CommonConstant.SPONSOR_MIXED.equals(tmMcMoneyOffInfo.getSponsor())) {
                            moneyOffAmountData.setBankDiscountLimitAmt(mcSubsidyData.getBankDiscountLimitAmt());
                            moneyOffAmountData.setMchntDiscountLimitAmt(mcSubsidyData.getMchntDiscountLimitAmt());
                        }

                        rglog.debug("TOTAL_SUBSIDY=<{}>, BANK_SUBSIDY=<{}>, MCHNT_SUBSIDY=<{}>", mcSubsidyData.getTotalSubsidy(), mcSubsidyData.getBankSubsidy(), mcSubsidyData.getMchntSubsidy());

                        /* 获取交易额度上限 */
                        retCode = fetchAllToClientMcQuotaData(moneyOffAmountData);
                        if (CommonConstant.PROCESS_FAILED == retCode) {
                            rglog.info("获取机构<{}>的营销活动<{}>各维度限额和额度失败,本营销活动不予优惠!", globalInstId, mcNo);
                            continue;
                        }

                        rglog.debug("TOTAL_SUBSIDY=<{}>, BANK_SUBSIDY=<{}>, MCHNT_SUBSIDY=<{}>", mcSubsidyData.getTotalSubsidy(), mcSubsidyData.getBankSubsidy(), mcSubsidyData.getMchntSubsidy());

                        /* 判断交易额度上限 */
                        retCode = checkAllQuotaWithMcType(tmMcMoneyOffInfo, moneyOffAmountData);
                        if (CommonConstant.PROCESS_FAILED == retCode) {
                            rglog.info("机构<{}>的营销活动<{}>判断各维度限额和额度失败,本营销活动不予优惠!", globalInstId, mcNo);
                            continue;
                        }

                        rglog.debug("TOTAL_SUBSIDY=<{}>, BANK_SUBSIDY=<{}>, MCHNT_SUBSIDY=<{}>", mcSubsidyData.getTotalSubsidy(), mcSubsidyData.getBankSubsidy(), mcSubsidyData.getMchntSubsidy());

                        /* 本商户本营销活动最终优惠金额 */
                        PrePaymentAvailableMoneyOffMcInfoBean prePaymentAvailableMoneyOffMcInfoBean = convertMoneyOffInfo(tmMcMoneyOffInfo, tmMcMoneyOffRuleInfo, mcMoneyOffTxnData);
                        prePaymentAvailableMoneyOffMcInfoBeanList.add(prePaymentAvailableMoneyOffMcInfoBean);
                    }
                }
            }

            if (prePaymentAvailableMoneyOffMcInfoBeanList.isEmpty()) {
                return null;
            } else {
                return prePaymentAvailableMoneyOffMcInfoBeanList.stream().distinct().collect(Collectors.toList());
            }

        } catch (Exception e) {
            rglog.error(StringUtil.ExceptionToString(e));
            throw new BizException(RespCodeEnum.SYSTEM_ERROR.getRespCode(), RespCodeEnum.SYSTEM_ERROR.getRespDesc());
        }
    }

    /**
     * 查询用户已领取卡券列表信息
     *
     * @param instId 法人机构号
     * @param userId 用户ID
     * @return java.util.List<cc.rengu.igas.momp.common.entity.TMCouponInfo> 卡券信息表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/4/28 09:52
     */
    private List<TMCouponInfo> selectUserCouponBoundListInfo(String instId, String userId, String globalTxnDate) throws Exception {

        CouponInfoMapper couponInfoMapper = new CouponInfoMapperImpl();
        return couponInfoMapper.selectUserCouponBoundListInfo(instId, userId, globalTxnDate);
    }


    /**
     * 根据订单金额过滤卡券面额，仅返回卡券面额不超过最大订单金额的记录
     *
     * @param tmCouponInfoList         卡券信息表
     * @param paymentOrderInfoBeanList 订单明细对象
     * @return java.util.List<cc.rengu.igas.momp.common.entity.TMCouponInfo> 卡券信息表
     * @author Jinan Liu
     * @since 2020/4/28 11:47
     */
    private List<TMCouponInfo> filterateCouponViaOrderAmt(List<TMCouponInfo> tmCouponInfoList, List<PaymentOrderInfoBean> paymentOrderInfoBeanList) {

        /* 取所有子订单中最大的订单金额 */
        PaymentOrderInfoBean paymentOrderInfoBean = paymentOrderInfoBeanList.stream().max(Comparator.comparing(PaymentOrderInfoBean::getOrderAmtNumber)).get();
        BigDecimal maxOrderAmt = paymentOrderInfoBean.getOrderAmtNumber();
        rglog.info("所有子订单的最大订单金额是<{}>", maxOrderAmt.toString());

        /* 根据最大的订单金额筛选卡券面额，卡券面额不可超过最大订单金额 */
        List<TMCouponInfo> tmCouponInfoList1 = new ArrayList<>();
        for (TMCouponInfo tmCouponInfo : tmCouponInfoList) {

            BigDecimal couponAmt = new BigDecimal(tmCouponInfo.getCouponAmt()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

            if (CommonConstant.ZERO > couponAmt.compareTo(maxOrderAmt)) {
                tmCouponInfoList1.add(tmCouponInfo);
            }
        }

        return tmCouponInfoList1;
    }

    /**
     * 判断合并支付订单中的子订单中的商户是否参与了卡券对应的营销活动
     * 进一步判断子订单的订单金额是否超过了卡券的使用门槛
     *
     * @param tmCouponInfo             卡券信息表
     * @param paymentOrderInfoBeanList 订单明细对象
     * @return cc.rengu.igas.momp.common.entity.TMCouponInfo 卡券信息表
     * @author Jinan Liu
     * @since 2020/6/2 20:15
     */
    private TMCouponInfo checkCouponValidation(TMCouponInfo tmCouponInfo, List<PaymentOrderInfoBean> paymentOrderInfoBeanList) {

        String couponNo = tmCouponInfo.getCouponNo();
        String mcNo = tmCouponInfo.getMcNo();

        try {

            List<PaymentOrderInfoBean> paymentOrderInfoBeanList1 = new ArrayList<>();

            /* 直接使用订单明细中的商户号和营销活动编号,判断对应商户是否参与了卡券对应的营销活动 */
            for (PaymentOrderInfoBean paymentOrderInfoBean : paymentOrderInfoBeanList) {

                TMMcCouponInfo tmMcCouponInfo;
                String mchntNo = paymentOrderInfoBean.getMchntNo();

                /* 查询营销活动基本信息 */
                CpMcListInfoInObj cpMcListInfoInObj = new CpMcListInfoInObj();
                cpMcListInfoInObj.setInstId(globalInstId);
                cpMcListInfoInObj.setMcNo(mcNo);
                TBMchntBaseInfo tbMchntBaseInfo = tbMchntBaseInfoList.stream().filter(object -> object.getMchntNo().equals(mchntNo)).collect(Collectors.toList()).get(CommonConstant.ZERO);

                String mchntArea;
                //判断商户类型，如果是连锁门店商户，非独立清算的商户需要用上级的商户查询营销活动
                //商户性质
                String mchntType = tbMchntBaseInfo.getMchntType();
                //连锁商户号
                String chainMchntNo = tbMchntBaseInfo.getChainMchntNo();
                //是否独立维护商户资料
                String independentDataFlag = tbMchntBaseInfo.getIndependentDataFlag();
                //如果是非独立清算的，需要用上级的商户查询；独立清算的暂不处理，用自己的查询
                if ((CommonConstant.NO.equals(independentDataFlag) && MchntTypeEnum.CHAIN_MCHNT_STORE.getMchntType().equals(mchntType))) {
                    rglog.info("商户<{}> 商户类型为11:连锁商户门店，是否独立维护商户资料<{}> 非独立清算商户,获取营销活动时需根据上级商户<{}> 获取!", mchntNo, independentDataFlag, chainMchntNo);
                    //查询上级商户的基本信息
                    MchntInfoMapper mchntInfoMapper = new MchntInfoMapperImpl();
                    TBMchntBaseInfo chainMchntBaseInfo = mchntInfoMapper.selectMompMchntBaseInfoByPrimaryKey(globalInstId, chainMchntNo);
                    if (null == chainMchntBaseInfo) {
                        //查询不到商户信息，流程结束
                        rglog.error("查询当前商户<{}>的上级商户<{}>基本信息信息失败!", mchntNo, chainMchntNo);
                        continue;
                    }
                    mchntArea = chainMchntBaseInfo.getMchntArea();
                    cpMcListInfoInObj.setMchntNo(chainMchntNo);
                    cpMcListInfoInObj.setMchntArea(mchntArea);
                } else {
                    rglog.info("商户<{}> 是否独立维护商户资料<{}> 商户类型为<{}> 普通商户或独立清算商户，均使用当前商户号查询营销信息！", mchntNo, independentDataFlag, mchntType);
                    mchntArea = tbMchntBaseInfo.getMchntArea();
                    cpMcListInfoInObj.setMchntNo(mchntNo);
                    cpMcListInfoInObj.setMchntArea(mchntArea);
                }

                if (!StringUtil.isNullorEmpty(mchntArea)) {
                    /* 使用营销活动编号、商户号和商圈编号查询 */
                    tmMcCouponInfo = selectAvailableCouponMcDetailInfoByMchntWithArea(cpMcListInfoInObj);
                } else {
                    /* 使用营销活动编号和商户号查询 */
                    tmMcCouponInfo = selectAvailableCouponMcDetailInfoByMchnt(cpMcListInfoInObj);
                }
                if (null == tmMcCouponInfo) {
                    rglog.error("机构<{}>的卡券类营销活动<{}>不包含商户<{}>!", globalInstId, mcNo, cpMcListInfoInObj.getMchntNo());
                } else {
                    /* 取卡券规则信息 */
                    TMMcCouponRuleInfo tmMcCouponRuleInfo = selectCouponRuleInfoByPrimaryKey(globalInstId, mcNo, tmCouponInfo.getRuleIndex());
                    if (null == tmMcCouponRuleInfo) {
                        rglog.error("获取法人机构号<{}>的卡券营销活动<{}>的规则信息<{}>失败!", globalInstId, mcNo, tmCouponInfo.getRuleIndex());
                        return null;
                    }
                    //判断卡券是否在可用优惠时间段内
                    /* 判断是否在营销活动允许的时间范围内-无需记录对应的时间规则 */
                    if (CommonConstant.ALL_TIME_SUPPORT.equals(tmMcCouponInfo.getMcTimeFlag())) {
                        rglog.info("机构<{}>的营销活动<{}>在任意时间段内可用!", globalInstId, mcNo);
                    } else if (CommonConstant.SPECIFIC_TIME_SUPPORT.equals(tmMcCouponInfo.getMcTimeFlag())) {
                        rglog.info("机构<{}>的营销活动<{}>在指定时间段内可用,需要进一步判断当前时间!", globalInstId, mcNo);
                        List<TMMcTimeInfo> tmMcTimeInfoList = getAllMcTimeListInfo(globalInstId, mcNo);
                        if (null == tmMcTimeInfoList || tmMcTimeInfoList.isEmpty()) {
                            rglog.info("获取机构<{}>的营销活动<{}>时间规则信息失败,本营销活动不予优惠!", globalInstId, mcNo);
                            continue;
                        } else {
                            int retCode = checkMcTimeInfo(globalTxnDate, globalTxnTime, tmMcTimeInfoList);
                            if (CommonConstant.PROCESS_SUCCESS != retCode) {
                                rglog.info("获取机构<{}>的营销活动<{}>时间规则信息匹配失败,本营销活动不予优惠!", globalInstId, mcNo);
                                continue;
                            } else {
                                rglog.info("获取机构<{}>的营销活动<{}>时间规则信息匹配成功,本营销活动可以优惠!", globalInstId, mcNo);
                            }
                        }
                    } else {
                        rglog.error("机构<{}>的营销活动<{}>活动时间标志<{}>异常,本营销活动不予优惠!", globalInstId, mcNo, tmMcCouponInfo.getMcTimeFlag());
                        continue;
                    }
                    //查询该用户，活动下的营销用户信息表信息
                    List<TMMcUserInfo> userInfoList = checkUserInfo(globalInstId, mcNo, globalUserId);
                    //测试账户
                    List<TMMcUserInfo> testUserInfoList = new ArrayList<>();
                    //正式账户
                    List<TMMcUserInfo> formalUserInfoList = new ArrayList<>();
                    if (null != userInfoList && userInfoList.size() > 0) {
                        testUserInfoList = userInfoList.stream().filter(item -> item.getAcctFlag().equals(CommonConstant.ACCT_FLAG_TESTING)).collect(Collectors.toList());
                        formalUserInfoList = userInfoList.stream().filter(item -> item.getAcctFlag().equals(CommonConstant.ACCT_FLAG_NORMAL)).collect(Collectors.toList());
                    }
                    /* 判断用户是否在营销活动允许的用户范围内-无需记录对应的用户规则 */
                    if (CommonConstant.ALL_CLIENT_SUPPORT.equals(tmMcCouponInfo.getClientRange())) {
                        rglog.info("机构<{}>的营销活动<{}>支持对所有用户减免,继续校验后续信息!", globalInstId, mcNo);
                        if (tmMcCouponInfo.getMcStatus().equals(McStatusEnum.TESTING.getMcStatusCode()) && testUserInfoList.size() == 0) {
                            rglog.info("获取机构<{}>的营销活动<{}>用户信息匹配失败,本营销活动不予优惠!", globalInstId, mcNo);
                            continue;
                        }

                        //判断用户参与活动次数是否超过活动配置的限制次数——不限定用户
                        Boolean userAttendIsReachLimit = checkIsUserReachLimit(tmMcCouponInfo, null);
                        if (!userAttendIsReachLimit) {
                            rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数大于等于最大限制，卡券无法使用！", globalUserId, mcNo);
                            continue;
                        }

                    } else if (CommonConstant.SPECIFIC_CLIENT_SUPPORT.equals(tmMcCouponInfo.getClientRange())) {
                        rglog.info("机构<{}>的营销活动<{}>支持对部分用户减免,需要进一步判断当前用!", globalInstId, mcNo);
                        ;
                        if (formalUserInfoList.size() > 0 && tmMcCouponInfo.getMcStatus().equals(McStatusEnum.PROGRESSING.getMcStatusCode())) {
                            rglog.info("获取机构<{}>的营销活动<{}>用户信息匹配成功,继续校验后续信息!", globalInstId, mcNo);

                            //判断用户参与活动次数是否超过活动配置的限制次数——正式用户
                            Boolean userAttendIsReachLimit = checkIsUserReachLimit(tmMcCouponInfo, formalUserInfoList);
                            if (!userAttendIsReachLimit) {
                                rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数大于等于最大限制，卡券无法使用！", globalUserId, mcNo);
                                continue;
                            }

                        } else if (testUserInfoList.size() > 0 && tmMcCouponInfo.getMcStatus().equals(McStatusEnum.TESTING.getMcStatusCode())) {
                            rglog.info("获取机构<{}>的营销活动<{}>用户信息匹配成功,继续校验后续信息!", globalInstId, mcNo);

                            //判断用户参与活动次数是否超过活动配置的限制次数——测试用户
                            Boolean userAttendIsReachLimit = checkIsUserReachLimit(tmMcCouponInfo, testUserInfoList);
                            if (!userAttendIsReachLimit) {
                                rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数大于等于最大限制，卡券无法使用！", globalUserId, mcNo);
                                continue;
                            }
                        } else {
                            rglog.info("获取机构<{}>的营销活动<{}>用户信息匹配失败,本营销活动不予优惠!", globalInstId, mcNo);
                            continue;
                        }
                    } else {
                        rglog.error("机构<{}>的营销活动<{}>客户范围<{}>异常,本营销活动不予优惠!", globalInstId, mcNo, tmMcCouponInfo.getClientRange());
                        continue;
                    }
                    //卡券类
                    McCouponTxnData mcCouponTxnData = new McCouponTxnData();
                    mcCouponTxnData.setMchntNo(cpMcListInfoInObj.getMchntNo());
                    //营销活动赋值
                    convertCouponMcInfo(tmMcCouponInfo, mcCouponTxnData);
                    //营销活动规则赋值
                    copyCoupnRuleInfoAmountData(tmMcCouponRuleInfo, mcCouponTxnData);
                    //获取卡券类各维度统计数据（交易限额）
                    int returnCode = fetchAllToClientMcQuotaData(mcCouponTxnData);
                    if (returnCode != CommonConstant.PROCESS_SUCCESS) {
                        rglog.info("获取活动<{}>各维度统计报表失败,不参与优惠！！！！", mcCouponTxnData.getMcNo());
                        continue;
                    }
                    //判断交易限额
                    returnCode = checkCouponLimits(mcCouponTxnData);
                    if (returnCode != CommonConstant.PROCESS_SUCCESS) {
                        rglog.info("判断交易限额失败,不参与优惠！！！！", mcCouponTxnData.getMcNo());
                        continue;
                    }

                    /* 生成卡券规则描述 */
                    tmCouponInfo.setRuleContent(generateCouponRuleContent(tmMcCouponRuleInfo));

                    //赋值营销活动对应的每个客户的参与次数限制
                    tmCouponInfo.setRemark1(tmMcCouponInfo.getRestriction());

                    paymentOrderInfoBeanList1.add(paymentOrderInfoBean);
                }
            }

            /* 未取到对应记录 */
            if (CommonConstant.ZERO == paymentOrderInfoBeanList1.size()) {
                rglog.info("卡券编号<{}>未在订单中匹配到支持的商户,不返回给渠道!", couponNo);
                return null;
            }
            /* 订单金额需大于等于卡券门槛金额,订单金额需大于卡券面额 */
            BigDecimal criteria = new BigDecimal(tmCouponInfo.getCriteria()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            BigDecimal couponAmt = new BigDecimal(tmCouponInfo.getCouponAmt()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            List<PaymentOrderInfoBean> paymentOrderInfoBeanList2 = paymentOrderInfoBeanList1.stream().filter(item -> ((CommonConstant.ZERO <= item.getOrderAmtNumber().compareTo(criteria)) && (CommonConstant.ZERO < item.getOrderAmtNumber().compareTo(couponAmt)))).collect(Collectors.toList());
            if (paymentOrderInfoBeanList2.isEmpty()) {
                rglog.info("未匹配到满足卡券使用门槛的订单信息!");
                return null;
            } else {
                return tmCouponInfo;
            }

        } catch (Exception e) {
            rglog.error(StringUtil.ExceptionToString(e));
            throw new BizException(RespCodeEnum.SYSTEM_ERROR.getRespCode(), RespCodeEnum.SYSTEM_ERROR.getRespDesc());
        }
    }

    /**
     * 商户查询营销活动基本信息表数据
     *
     * @param cpMcListInfoInObj 营销活动列表查询使用实体类入参
     * @return cc.rengu.igas.momp.common.entity.TMMcCouponInfo 卡券类营销活动信息表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/5/28 19:10
     */
    private TMMcCouponInfo selectAvailableCouponMcDetailInfoByMchnt(CpMcListInfoInObj cpMcListInfoInObj) throws Exception {
        McDetailInfoMapper mcDetailInfoMapper = new McDetailInfoMapperImpl();
        return mcDetailInfoMapper.selectAvailableCouponMcDetailInfoByMchnt(cpMcListInfoInObj);
    }

    /**
     * 商户查询营销活动基本信息表数据
     *
     * @param cpMcListInfoInObj 营销活动列表查询使用实体类入参
     * @return cc.rengu.igas.momp.common.entity.TMMcCouponInfo 卡券类营销活动信息表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/5/28 19:10
     */
    private TMMcCouponInfo selectAvailableCouponMcDetailInfoByMchntWithArea(CpMcListInfoInObj cpMcListInfoInObj) throws Exception {
        McDetailInfoMapper mcDetailInfoMapper = new McDetailInfoMapperImpl();
        return mcDetailInfoMapper.selectAvailableCouponMcDetailInfoByMchntWithArea(cpMcListInfoInObj);
    }

    /**
     * 根据卡券规则信息表主键获取单条卡券规则信息
     *
     * @param instId    法人机构号
     * @param mcNo      营销活动编号
     * @param ruleIndex 规则顺序号
     * @return cc.rengu.igas.momp.common.entity.TMMcCouponRuleInfo 卡券类营销活动规则信息表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/6/2 21:39
     */
    private TMMcCouponRuleInfo selectCouponRuleInfoByPrimaryKey(String instId, String mcNo, String ruleIndex) throws Exception {

        McRuleInfoMapper mcRuleInfoMapper = new McRuleInfoMapperImpl();
        return mcRuleInfoMapper.selectCouponRuleInfoByPrimaryKey(instId, mcNo, ruleIndex);
    }

    /**
     * 根据卡券规则信息生成卡券规则信息描述
     *
     * @param tmMcCouponRuleInfo 卡券类营销活动规则信息表
     * @return java.lang.String 卡券规则信息描述
     * @author Jinan Liu
     * @since 2020/6/2 21:45
     */
    private String generateCouponRuleContent(TMMcCouponRuleInfo tmMcCouponRuleInfo) {

        BigDecimal criteria = new BigDecimal(tmMcCouponRuleInfo.getCriteria()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
        BigDecimal denomination = new BigDecimal(tmMcCouponRuleInfo.getDenomination()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        return "满" + criteria.toString() + "减" + denomination.toString();
    }

    /**
     * 卡券信息数据库实体类和应答报文实体类转换
     *
     * @param tmCouponInfo 卡券信息表
     * @return cc.rengu.igas.momp.facade.bean.CouponListInfoBean 卡券列表信息对象
     * @author Jinan Liu
     * @since 2020/6/2 21:22
     */
    private PrePaymentAvailableCouponMcInfoBean convertCouponInfo(TMCouponInfo tmCouponInfo) {

        PrePaymentAvailableCouponMcInfoBean prePaymentAvailableCouponMcInfoBean = new PrePaymentAvailableCouponMcInfoBean();

        /* 卡券编号 */
        prePaymentAvailableCouponMcInfoBean.setCouponNo(tmCouponInfo.getCouponNo());
        /* 卡券有效起始日期 */
        prePaymentAvailableCouponMcInfoBean.setCouponStartDate(tmCouponInfo.getCouponStartDate());
        /* 卡券有效结束日期 */
        prePaymentAvailableCouponMcInfoBean.setCouponEndDate(tmCouponInfo.getCouponEndDate());
        /* 领取日期 */
        prePaymentAvailableCouponMcInfoBean.setClaimDate(tmCouponInfo.getClaimDate());
        /* 领取时间 */
        prePaymentAvailableCouponMcInfoBean.setClaimTime(tmCouponInfo.getClaimTime());
        /* 卡券状态 */
        prePaymentAvailableCouponMcInfoBean.setCouponStatus(tmCouponInfo.getCouponStatus());
        /* 卡券可抵扣金额 */
        prePaymentAvailableCouponMcInfoBean.setCouponAmt(tmCouponInfo.getCouponAmt());
        /* 活动门槛 */
        prePaymentAvailableCouponMcInfoBean.setCriteria(tmCouponInfo.getCriteria());
        /* 卡券领取方式 */
        prePaymentAvailableCouponMcInfoBean.setClaimType(tmCouponInfo.getClaimType());
        /* 卡券规则描述 */
        prePaymentAvailableCouponMcInfoBean.setRuleContent(tmCouponInfo.getRuleContent());
        /* 当前该卡券是否可使用 */
        prePaymentAvailableCouponMcInfoBean.setCouponCanUse(CommonConstant.COUPON_AVAILABLE_YES);

//        createCouponOprLog(tmCouponInfo);

        return prePaymentAvailableCouponMcInfoBean;
    }

    /**
     * 使用商户号和商户所在商圈编号匹配营销活动商户信息表中数据
     *
     * @param mchntBaseInfo 商户基本信息表T_B_MCHNT_BASE_INFO
     * @return java.util.List<cc.rengu.igas.momp.common.entity.TMMcMchntInfo> 营销活动商户信息表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/4/13 15:10
     */
    private List<TMMcMchntInfo> matchMcMchntInfoByUsingMchntInfo(TBMchntBaseInfo mchntBaseInfo) throws Exception {

        McMchntInfoMapper mcMchntInfoMapper = new McMchntInfoMapperImpl();
        return mcMchntInfoMapper.matchMoMcInfoByMchntNoAndMchntArea(mchntBaseInfo);
    }

    /**
     * 减免类请求报文转换内部对象
     *
     * @param paymentOrderInfoBean 订单明细对象
     * @return cc.rengu.igas.momp.common.entity.McMoneyOffTxnData (合并)支付使用减免类交易信息
     * @author Jinan Liu
     * @since 2020/6/2 22:11
     */
    private McMoneyOffTxnData convertMoneyOffInfoData(PaymentOrderInfoBean paymentOrderInfoBean) {

        McMoneyOffTxnData mcMoneyOffTxnData = new McMoneyOffTxnData();

        /* 交易日期 */
        mcMoneyOffTxnData.setTransDate(globalTxnDate);
        /* 交易时间 */
        mcMoneyOffTxnData.setTransTime(globalTxnTime);
        /* 机构编码 */
        mcMoneyOffTxnData.setInstId(globalInstId);
        /* 商户编号 */
        mcMoneyOffTxnData.setMchntNo(paymentOrderInfoBean.getMchntNo());
        /* 订单金额 */
        mcMoneyOffTxnData.setOrderAmt(paymentOrderInfoBean.getOrderAmt());
        /* 用户编号 */
        mcMoneyOffTxnData.setUserId(globalUserId);

        return mcMoneyOffTxnData;
    }

    /**
     * 使用营销活动商户信息对象获取营销活动基本信息
     *
     * @param tmMcMchntInfo        营销活动商户信息表
     * @param tmMcMoneyOffInfoList 减免类营销活动信息表
     * @author Jinan Liu
     * @since 2020/4/14 09:44
     */
    private void getMoneyOffMcInfo(TMMcMchntInfo tmMcMchntInfo, List<TMMcMoneyOffInfo> tmMcMoneyOffInfoList) {

        String instId = tmMcMchntInfo.getInstId();
        String mcNo = tmMcMchntInfo.getMcNo();

        try {
            /* 根据营销活动状态查询营销活动信息,必须是进行中或测试中的营销活动才可以查询到 */
            McDetailInfoMapper mcDetailInfoMapper = new McDetailInfoMapperImpl();
            TMMcMoneyOffInfo mcMoneyOffInfo = mcDetailInfoMapper.selectMoMcDetailInfoByMcStatus(instId, mcNo, McStatusEnum.PROGRESSING.getMcStatusCode());
            if (null == mcMoneyOffInfo) {
                rglog.error("机构<{}>的减免类营销活动<{}>信息查询失败!", instId, mcNo);
            } else {
                if (tmMcMchntInfo.getExitFlag().equals(CommonConstant.MC_NOT_EXIT_FLAG) && tmMcMchntInfo.getNewMchntFlag().equals(CommonConstant.MCHNT_OLD_FLAG) ||
                        tmMcMchntInfo.getExitFlag().equals(CommonConstant.MC_NOT_EXIT_FLAG) && tmMcMchntInfo.getNewMchntFlag().equals(CommonConstant.MCHNT_NEW_FLAG)) {
                    tmMcMoneyOffInfoList.add(mcMoneyOffInfo);
                } else {
                    rglog.info("法人机构<{}>的商户<{}>未参加减免类营销活动<{}>!NEW_MCHNT_FLAG<{}>,EXIT_FLAG<{}>", globalInstId, tmMcMchntInfo.getMchntNo(), mcNo, tmMcMchntInfo.getNewMchntFlag(), tmMcMchntInfo.getExitFlag());
                }
            }
        } catch (Exception e) {
            rglog.error("机构<{}>的减免类营销活动<{}>信息查询失败!", instId, mcNo);
        }
    }

    /**
     * 检查营销活动状态及当前系统日期是否在营销活动有效期内
     *
     * @param tmMcMoneyOffInfo 减免类营销活动信息表
     * @param mchntNo          商户编号
     * @return int 返回码
     * @author Jinan Liu
     * @since 2020/4/14 10:00
     */
    private int checkMcStatus(TMMcMoneyOffInfo tmMcMoneyOffInfo, String mchntNo) {

        String mcStatus = tmMcMoneyOffInfo.getMcStatus();

        /* 判断营销活动状态是否是进行中 */
        if (!McStatusEnum.PROGRESSING.getMcStatusCode().equals(mcStatus)) {
            rglog.error("{}, INST_ID=<{}>, MC_NO=<{}>, MC_STATUS=<{}>",
                    RespCodeEnum.WRONG_MC_STATUS_TO_DISCOUNT_ERROR.getRespDesc(), globalInstId, mcStatus);
            return CommonConstant.PROCESS_FAILED;
        }

        String mcStartDate = tmMcMoneyOffInfo.getMcStartDate();
        String mcEndDate = tmMcMoneyOffInfo.getMcEndDate();

        int returnCode = MompDateUtil.checkDateRange(globalTxnDate, mcStartDate, mcEndDate);
        if (CommonConstant.ZERO != returnCode) {
            rglog.error("当前交易日期<{}>未在营销活动的有效期<{}>-<{}>内,机构<{}>的商户<{}>不可参加减免类优惠活动<{}>",
                    globalTxnDate, mcStartDate, mcEndDate, globalInstId, mchntNo, tmMcMoneyOffInfo.getMcNo());
            return CommonConstant.PROCESS_FAILED;
        }

        return CommonConstant.PROCESS_SUCCESS;
    }

    /**
     * 使用营销活动编号查询营销活动所有时间规则信息
     *
     * @param instId 法人机构号
     * @param mcNo   营销活动编号
     * @return java.util.List<cc.rengu.igas.momp.common.entity.TMMcTimeInfo> 营销活动时间信息表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/4/14 11:35
     */
    private List<TMMcTimeInfo> getAllMcTimeListInfo(String instId, String mcNo) throws Exception {

        McTimeInfoMapper mcTimeInfoMapper = new McTimeInfoMapperImpl();
        List<TMMcTimeInfo> tmMcTimeInfoList = mcTimeInfoMapper.selectMcTimeInfoList(instId, mcNo);
        if (null == tmMcTimeInfoList || tmMcTimeInfoList.isEmpty()) {
            return null;
        } else {
            return tmMcTimeInfoList;
        }
    }

    /**
     * 检查当前时间是否在营销活动允许时间范围内
     * 在时间范围内返回0
     * 不在时间范围内返回-1
     *
     * @param transDate        当前交易日期
     * @param transTime        当前交易时间
     * @param tmMcTimeInfoList 营销活动时间信息表
     * @return int 返回码
     * @author Jinan Liu
     * @since 2020/4/14 14:34
     */
    private int checkMcTimeInfo(String transDate, String transTime, List<TMMcTimeInfo> tmMcTimeInfoList) {

        int returnCode;
        int matchFlag = CommonConstant.FLAG_NOT_SET;

        /* 获取当前日期对应星期几 */
        MompDateUtil mompDateUtil = new MompDateUtil();
        int dayOfWeek = mompDateUtil.getWeek(transDate);

        for (TMMcTimeInfo tmMcTimeInfo : tmMcTimeInfoList) {
            returnCode = checkMcTimeWeekInfo(dayOfWeek, tmMcTimeInfo);
            if (returnCode != CommonConstant.PROCESS_SUCCESS) {
                /* 未匹配到满足条件的星期X,继续判断下一组时间规则 */
                rglog.debug("未匹配到满足条件的星期X,继续判断下一组时间规则");
            } else {
                /* 匹配到满足条件的星期X,进一步判断时间范围是否满足条件 */
                int retCode = checkMcTimeRangeInfo(transTime, tmMcTimeInfo);
                if (CommonConstant.PROCESS_SUCCESS == retCode) {
                    /* 时间规则匹配成功 */
                    rglog.debug("时间规则匹配成功");
                    matchFlag = CommonConstant.FLAG_SET;
                    break;
                } else {
                    /* 时间规则匹配失败,需要继续判断下一组时间规则 */
                    rglog.debug("时间规则匹配失败,需要继续判断下一组时间规则");
                }
            }
        }

        /* 时间规则匹配成功即可,无需记录对应信息 */
        if (CommonConstant.FLAG_SET == matchFlag) {
            return CommonConstant.PROCESS_SUCCESS;
        } else {
            return CommonConstant.PROCESS_FAILED;
        }
    }

    /**
     * 判断营销活动时间规则是否支持
     * 支持返回0
     * 不支持返回-1
     *
     * @param dayOfWeek    星期几
     * @param tmMcTimeInfo 营销活动时间信息表
     * @return int 返回码
     * @author Jinan Liu
     * @since 2020/4/14 15:25
     */
    private int checkMcTimeWeekInfo(int dayOfWeek, TMMcTimeInfo tmMcTimeInfo) {

        String weekString = tmMcTimeInfo.getFlagMonday() + tmMcTimeInfo.getFlagTuesday() + tmMcTimeInfo.getFlagWednesday()
                + tmMcTimeInfo.getFlagThursday() + tmMcTimeInfo.getFlagFriday() + tmMcTimeInfo.getFlagSaturday() + tmMcTimeInfo.getFlagSunday();

        if (CommonConstant.WEEK_FLAG_ALL_NOT_SET.equals(weekString) || CommonConstant.WEEK_FLAG_ALL_SET.equals(weekString)) {
            /* 不区分星期一至星期日 */
            return CommonConstant.PROCESS_SUCCESS;
        } else {
            /* 区分星期一至星期日 */
            switch (dayOfWeek) {
                case CommonConstant.WEEK_MONDAY:
                    if (CommonConstant.WEEK_FLAG_SET.equals(tmMcTimeInfo.getFlagMonday())) {
                        return CommonConstant.PROCESS_SUCCESS;
                    }
                    break;
                case CommonConstant.WEEK_TUESDAY:
                    if (CommonConstant.WEEK_FLAG_SET.equals(tmMcTimeInfo.getFlagTuesday())) {
                        return CommonConstant.PROCESS_SUCCESS;
                    }
                    break;
                case CommonConstant.WEEK_WEDNESDAY:
                    if (CommonConstant.WEEK_FLAG_SET.equals(tmMcTimeInfo.getFlagWednesday())) {
                        return CommonConstant.PROCESS_SUCCESS;
                    }
                    break;
                case CommonConstant.WEEK_THURSDAY:
                    if (CommonConstant.WEEK_FLAG_SET.equals(tmMcTimeInfo.getFlagThursday())) {
                        return CommonConstant.PROCESS_SUCCESS;
                    }
                    break;
                case CommonConstant.WEEK_FRIDAY:
                    if (CommonConstant.WEEK_FLAG_SET.equals(tmMcTimeInfo.getFlagFriday())) {
                        return CommonConstant.PROCESS_SUCCESS;
                    }
                    break;
                case CommonConstant.WEEK_SATURDAY:
                    if (CommonConstant.WEEK_FLAG_SET.equals(tmMcTimeInfo.getFlagSaturday())) {
                        return CommonConstant.PROCESS_SUCCESS;
                    }
                    break;
                case CommonConstant.WEEK_SUNDAY:
                    if (CommonConstant.WEEK_FLAG_SET.equals(tmMcTimeInfo.getFlagSunday())) {
                        return CommonConstant.PROCESS_SUCCESS;
                    }
                    break;
                default:
                    rglog.error("错误的日期,DAY_OF_WEEK=<{}>", dayOfWeek);
                    return CommonConstant.PROCESS_FAILED;
            }
            return CommonConstant.PROCESS_FAILED;
        }

    }

    /**
     * 判断营销活动时间范围是否支持
     * 在时间范围内返回0
     * 未在时间范围内返回-1
     *
     * @param transTime    交易时间
     * @param tmMcTimeInfo 营销活动时间信息表
     * @return int 返回码
     * @author Jinan Liu
     * @since 2020/4/14 15:26
     */
    private int checkMcTimeRangeInfo(String transTime, TMMcTimeInfo tmMcTimeInfo) {

        BigDecimal currentTime = new BigDecimal(transTime).setScale(CommonConstant.ZERO, RoundingMode.HALF_UP);
        BigDecimal startTime = new BigDecimal(tmMcTimeInfo.getStartTime().trim().concat("0000")).setScale(CommonConstant.ZERO, RoundingMode.HALF_UP);
        BigDecimal endTime = new BigDecimal(tmMcTimeInfo.getEndTime().trim().concat("0000")).setScale(CommonConstant.ZERO, RoundingMode.HALF_UP);

        if (CommonConstant.ZERO <= (currentTime.compareTo(startTime)) &&
                (CommonConstant.ZERO >= currentTime.compareTo(endTime))) {
            /* 当前交易时间在营销活动时间范围内,时间规则判断通过 */
            return CommonConstant.PROCESS_SUCCESS;
        } else {
            /* 当前交易时间未在营销活动时间范围内,时间规则判断不通过 */
            return CommonConstant.PROCESS_FAILED;
        }
    }

    /**
     * 判断当前交易用户是否在用户白名单中
     * 在白名单中返回0
     * 未在白名单中返回-1
     *
     * @param instId 法人机构号
     * @param mcNo   营销活动编号
     * @param userId 用户ID
     * @return int 返回码
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/4/14 15:52
     */
    private List<TMMcUserInfo> checkUserInfo(String instId, String mcNo, String userId) throws Exception {

        //查询上送用户的卡bin信息
        BinInfoService binInfoService = new BinInfoServiceImpl();
        BinInfo binInfo = binInfoService.getCardBinInfo(userId);
        if (null != binInfo) {
            String binNo = binInfo.getBinNo();
            rglog.info("通过用户号<{}> 查询卡bin信息为 <{}>！", userId, binNo);
            userId = userId + "," + binNo;
        } else {
            rglog.info("通过用户号<{}> 查询卡bin信息为空！", userId);
        }

        McUserInfoMapper mcUserInfoMapper = new McUserInfoMapperImpl();

        return mcUserInfoMapper.selectMcUserInfoListByInstIdMcNoAcctNo(instId, mcNo, userId);
    }

    /**
     * 查询减免类营销活动规则信息
     *
     * @param instId 法人机构号
     * @param mcNo   营销活动编号
     * @return cc.rengu.igas.momp.common.entity.TMMcMoneyOffRuleInfo 减免类营销活动规则表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/6/2 22:27
     */
    private List<TMMcMoneyOffRuleInfo> selectMoneyOffRuleInfoList(String instId, String mcNo) throws Exception {

        McRuleInfoMapper mcRuleInfoMapper = new McRuleInfoMapperImpl();
        return mcRuleInfoMapper.selectMoneyOffRuleInfoList(instId, mcNo);
    }

    /**
     * 减免类规则信息赋值
     *
     * @param tmMcMoneyOffRuleInfo 减免类营销活动规则表
     * @param moneyOffAmountData   减免类营销活动金额数据
     * @author Jinan Liu
     * @since 2020/4/15 13:52
     */
    private void copyMoneyOffRuleInfoAmountData(TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo, MoneyOffAmountData moneyOffAmountData) {

        /* 法人机构号 */
        moneyOffAmountData.setInstId(tmMcMoneyOffRuleInfo.getInstId());
        /* 营销活动编号 */
        moneyOffAmountData.setMcNo(tmMcMoneyOffRuleInfo.getMcNo());
        /* 规则信息-顺序号 */
        moneyOffAmountData.setRuleIndex(tmMcMoneyOffRuleInfo.getRuleIndex());
        /* 规则信息-活动门槛 */
        moneyOffAmountData.setCriteria(tmMcMoneyOffRuleInfo.getCriteria());
        /* 规则信息-优惠力度下限 */
        moneyOffAmountData.setDiscountFloor(tmMcMoneyOffRuleInfo.getDiscountFloor());
        /* 规则信息-优惠力度上限 */
        moneyOffAmountData.setDiscountCelling(tmMcMoneyOffRuleInfo.getDiscountCelling());
        /* 规则信息-总优惠数量 */
        moneyOffAmountData.setDiscountQuantity(tmMcMoneyOffRuleInfo.getDiscountQuantity());
        /* 规则信息-单次优惠限制 */
        moneyOffAmountData.setDiscountLimit(tmMcMoneyOffRuleInfo.getDiscountLimit());
        /* 规则信息-优惠总预算 */
        moneyOffAmountData.setRuleBudget(tmMcMoneyOffRuleInfo.getBudget());
        /* 规则信息-单日消耗预算 */
        moneyOffAmountData.setBudgetDayLimit(tmMcMoneyOffRuleInfo.getBudgetDayLimit());
    }

    /**
     * 根据营销活动种类和规则计算补贴减免金额
     *
     * @param mcMoneyOffTxnData    (合并)支付使用减免类交易信息
     * @param mcType               营销活动类型
     * @param tmMcMoneyOffRuleInfo 减免类营销活动规则表
     * @return java.lang.String
     * @author Jinan Liu
     * @since 2020/4/18 19:55
     */
    private String calculateMcDiscountAmount(McMoneyOffTxnData mcMoneyOffTxnData, String mcType, TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo) {

        if (!StringUtil.isNullorEmpty(mcType)) {
            switch (McTypeEnum.getByValue(mcType)) {
                case REDUCTION_FIXED_AMOUNT:
                    /* 满额立减固定金额 */
                    return calculateReductionFixedAmount(mcMoneyOffTxnData, tmMcMoneyOffRuleInfo);
                case REDUCTION_RANDOM_AMOUNT:
                    /* 满额立减随机金额 */
                    return calculateReductionRandomAmount(mcMoneyOffTxnData, tmMcMoneyOffRuleInfo);
                case REDUCTION_FIXED_RATE:
                    /* 满额固定折扣 */
                    return calculateReductionFixedRate(mcMoneyOffTxnData, tmMcMoneyOffRuleInfo);
                case REDUCTION_RANDOM_RATE:
                    /* 满额随机折扣 */
                    return calculateReductionRandomRate(mcMoneyOffTxnData, tmMcMoneyOffRuleInfo);
                default:
                    /* 其他类型营销活动 */
                    return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 计算满额立减固定金额类活动减免金额
     *
     * @param mcMoneyOffTxnData    (合并)支付使用减免类交易信息
     * @param tmMcMoneyOffRuleInfo 减免类营销活动规则表
     * @return java.lang.String 补贴金额
     * @author Jinan Liu
     * @since 2020/4/14 17:54
     */
    private String calculateReductionFixedAmount(McMoneyOffTxnData mcMoneyOffTxnData, TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo) {

        BigDecimal totalSubsidy = new BigDecimal(tmMcMoneyOffRuleInfo.getDiscountCelling()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
        BigDecimal orderAmt = new BigDecimal(mcMoneyOffTxnData.getOrderAmt()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        mcMoneyOffTxnData.setFloorAmt(totalSubsidy.toString());
        mcMoneyOffTxnData.setCellingAmt(totalSubsidy.toString());

        rglog.debug("TOTAL_SUBSIDY=<{}>, ORDER_AMT=<{}>", totalSubsidy.toString(), orderAmt.toString());

        if (CommonConstant.ZERO < totalSubsidy.compareTo(orderAmt)) {
            /* 优惠金额大于等于订单金额,减不到指定金额则不进行优惠 */
            totalSubsidy = orderAmt;
        }

        rglog.info("优惠金额TOTAL_SUBSIDY=<{}>, 订单金额ORDER_AMT=<{}>", totalSubsidy.toString(), orderAmt.toString());

        return totalSubsidy.toString();
    }

    /**
     * 计算满额立减随机金额减免金额
     *
     * @param mcMoneyOffTxnData    (合并)支付使用减免类交易信息
     * @param tmMcMoneyOffRuleInfo 减免类营销活动规则表
     * @return java.lang.String 补贴金额
     * @author Jinan Liu
     * @since 2020/4/14 17:54
     */
    private String calculateReductionRandomAmount(McMoneyOffTxnData mcMoneyOffTxnData, TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo) {

        BigDecimal orderAmt = new BigDecimal(mcMoneyOffTxnData.getOrderAmt()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
        BigDecimal minValue = new BigDecimal(tmMcMoneyOffRuleInfo.getDiscountFloor()).setScale(CommonConstant.DECIMAL_SCALE_FIVE, RoundingMode.HALF_UP);
        BigDecimal maxValue = new BigDecimal(tmMcMoneyOffRuleInfo.getDiscountCelling()).setScale(CommonConstant.DECIMAL_SCALE_FIVE, RoundingMode.HALF_UP);

        mcMoneyOffTxnData.setFloorAmt(minValue.toString());
        mcMoneyOffTxnData.setCellingAmt(maxValue.toString());

        BigDecimal totalSubsidy = getRandomBetweenMinAndMax(minValue, maxValue);
        rglog.info("最初随机值为 ：TOTAL_SUBSIDY=<{}>", totalSubsidy.toString());

        if (CommonConstant.ZERO < totalSubsidy.compareTo(orderAmt)) {
            /* 优惠金额大于等于订单金额,优惠金额=订单金额 */
            totalSubsidy = orderAmt;
        }

        rglog.info("优惠金额TOTAL_SUBSIDY=<{}>, 订单金额ORDER_AMT=<{}>", totalSubsidy.toString(), orderAmt.toString());

        return totalSubsidy.toString();
    }

    /**
     * 计算满额固定折扣减免金额
     *
     * @param mcMoneyOffTxnData    (合并)支付使用减免类交易信息
     * @param tmMcMoneyOffRuleInfo 减免类营销活动规则表
     * @return java.lang.String 补贴金额
     * @author Jinan Liu
     * @since 2020/4/14 17:54
     */
    private String calculateReductionFixedRate(McMoneyOffTxnData mcMoneyOffTxnData, TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo) {

        BigDecimal orderAmt = new BigDecimal(mcMoneyOffTxnData.getOrderAmt());
        BigDecimal discountRate = BigDecimal.TEN.subtract(new BigDecimal(tmMcMoneyOffRuleInfo.getDiscountCelling())).divide(BigDecimal.TEN);
        BigDecimal discountLimit = new BigDecimal(tmMcMoneyOffRuleInfo.getDiscountLimit()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        BigDecimal totalSubsidy = orderAmt.multiply(discountRate).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        mcMoneyOffTxnData.setFloorAmt(totalSubsidy.toString());
        mcMoneyOffTxnData.setCellingAmt(totalSubsidy.toString());

        rglog.info("TOTAL_SUBSIDY=<{}>, DISCOUNT_LIMIT=<{}>", totalSubsidy.toString(), discountLimit.toString());

        if (CommonConstant.ZERO <= totalSubsidy.compareTo(discountLimit)) {
            /* 优惠金额大于等于优惠上限,优惠金额=优惠上限 */
            totalSubsidy = discountLimit;
            mcMoneyOffTxnData.setCellingAmt(totalSubsidy.toString());
        }

        rglog.info("TOTAL_SUBSIDY=<{}>, DISCOUNT_LIMIT=<{}>", totalSubsidy.toString(), discountLimit.toString());

        return totalSubsidy.toString();
    }

    /**
     * 计算满额随机折扣减免金额
     *
     * @param mcMoneyOffTxnData    (合并)支付使用减免类交易信息
     * @param tmMcMoneyOffRuleInfo 减免类营销活动规则表
     * @return java.lang.String 补贴金额
     * @author Jinan Liu
     * @since 2020/4/14 17:54
     */
    private String calculateReductionRandomRate(McMoneyOffTxnData mcMoneyOffTxnData, TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo) {

        BigDecimal orderAmt = new BigDecimal(mcMoneyOffTxnData.getOrderAmt());
        BigDecimal minDiscountRate = BigDecimal.TEN.subtract(new BigDecimal(tmMcMoneyOffRuleInfo.getDiscountFloor())).divide(BigDecimal.TEN);
        BigDecimal maxDiscountRate = BigDecimal.TEN.subtract(new BigDecimal(tmMcMoneyOffRuleInfo.getDiscountCelling())).divide(BigDecimal.TEN);
        BigDecimal discountLimit = new BigDecimal(tmMcMoneyOffRuleInfo.getDiscountLimit()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        BigDecimal minTotalSubsidy = orderAmt.multiply(minDiscountRate).setScale(CommonConstant.DECIMAL_SCALE_FIVE, RoundingMode.HALF_UP);
        BigDecimal maxTotalSubsidy = orderAmt.multiply(maxDiscountRate).setScale(CommonConstant.DECIMAL_SCALE_FIVE, RoundingMode.HALF_UP);

        BigDecimal totalSubsidy = getRandomBetweenMinAndMax(minTotalSubsidy, maxTotalSubsidy);

        mcMoneyOffTxnData.setFloorAmt(minTotalSubsidy.toString());
        mcMoneyOffTxnData.setCellingAmt(maxTotalSubsidy.toString());

        rglog.info("TOTAL_SUBSIDY=<{}>, DISCOUNT_LIMIT=<{}>", totalSubsidy.toString(), discountLimit.toString());

        if (CommonConstant.ZERO <= totalSubsidy.compareTo(discountLimit)) {
            /* 优惠金额大于等于优惠上限,优惠金额=优惠上限 */
            totalSubsidy = discountLimit;
        }

        rglog.info("TOTAL_SUBSIDY=<{}>, DISCOUNT_LIMIT=<{}>", totalSubsidy.toString(), discountLimit.toString());

        return totalSubsidy.toString();

    }

    /**
     * 生成范围内随机数
     *
     * @param minValue 最小值
     * @param maxValue 最大值
     * @return java.math.BigDecimal 生成的随机数
     * @author liujinan
     * @since 2020/8/26 20:45
     */
    private BigDecimal getRandomBetweenMinAndMax(BigDecimal minValue, BigDecimal maxValue) {
        /* 生成随机数 范围为 [0,1) */
        double randoms = new SecureRandom().nextDouble();
        BigDecimal random = BigDecimal.valueOf(randoms);
        rglog.info("生成的随机盐值:<{}>", random.toString());
        BigDecimal discount = random.multiply(maxValue.subtract(minValue)).add(minValue).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        if (CommonConstant.ZERO == discount.compareTo(maxValue)) {
            return discount.subtract(BigDecimal.ONE.divide(BigDecimal.TEN).divide(BigDecimal.TEN)).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
        } else {
            return discount;
        }
    }

    /**
     * 计算银行和商户营销资金出资金额
     *
     * @param mcSubsidyData 营销活动补贴数据对象
     * @return int 返回码
     * @author Jinan Liu
     * @since 2020/4/18 21:58
     */
    private int calculateBankAndMchntSubsidyRatio(McSubsidyData mcSubsidyData) {

        if (!StringUtil.isNullorEmpty(mcSubsidyData.getMcType())) {
            switch (McTypeEnum.getByValue(mcSubsidyData.getMcType())) {
                case REDUCTION_FIXED_AMOUNT:
                case REDUCTION_RANDOM_AMOUNT:
                case REDUCTION_FIXED_RATE:
                case REDUCTION_RANDOM_RATE:
                    switch (mcSubsidyData.getSponsor()) {
                        case CommonConstant.SPONSOR_BANK:
                            /* 银行全资 */
                            mcSubsidyData.setBankSubsidy(mcSubsidyData.getTotalSubsidy());
                            mcSubsidyData.setMchntSubsidy(BigDecimal.ZERO.setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP).toString());
                            return CommonConstant.PROCESS_SUCCESS;
                        case CommonConstant.SPONSOR_MIXED:
                            /* 银行、商户合资 */
                            String bankRatio = mcSubsidyData.getBankBudgetRatio();
                            BigDecimal totalAmt = new BigDecimal(mcSubsidyData.getTotalSubsidy()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                            BigDecimal bankAmt = new BigDecimal(bankRatio).multiply(totalAmt).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                            BigDecimal mchntAmt = totalAmt.subtract(bankAmt).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

                            mcSubsidyData.setBankSubsidy(bankAmt.toString());
                            mcSubsidyData.setMchntSubsidy(mchntAmt.toString());

                            /* 预算 */
                            BigDecimal budget = new BigDecimal(mcSubsidyData.getBudget()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                            /* 银行出资预算 */
                            BigDecimal bankBudget = new BigDecimal(mcSubsidyData.getBankBudget()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                            /* 预期参与商户数量 */
                            BigDecimal expectMchntQty = new BigDecimal(mcSubsidyData.getExpectMchntQty()).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);
                            if (CommonConstant.IS_EQUAL_TO == BigDecimal.ZERO.compareTo(expectMchntQty)) {
                                return CommonConstant.PROCESS_FAILED;
                            }

                            /* 计算商户累计优惠额度上限 */
                            mcSubsidyData.setBankDiscountLimitAmt(bankBudget.divide(expectMchntQty, CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP).toString());
                            mcSubsidyData.setMchntDiscountLimitAmt(budget.subtract(bankBudget).divide(expectMchntQty, CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP).toString());

                            return CommonConstant.PROCESS_SUCCESS;
                        case CommonConstant.SPONSOR_MCHNT:
                        case CommonConstant.SPONSOR_MCHNT_NORECHARGE:
                            /* 商户全资 */
                            mcSubsidyData.setBankSubsidy(BigDecimal.ZERO.setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP).toString());
                            mcSubsidyData.setMchntSubsidy(mcSubsidyData.getTotalSubsidy());
                            return CommonConstant.PROCESS_SUCCESS;
                        default:
                            rglog.error("错误的营销活动出资方式, SPONSOR=<{}>", mcSubsidyData.getSponsor());
                            return CommonConstant.PROCESS_FAILED;
                    }
                default:
                    rglog.error("营销活动类型<{}>异常,不可计算银行与商户出资比例!", mcSubsidyData.getMcType());
                    return CommonConstant.PROCESS_FAILED;
            }
        } else {
            return CommonConstant.PROCESS_FAILED;
        }
    }

    /**
     * 取对客类营销活动各维度统计数据
     *
     * @param object 营销活动金额数据
     * @return int 返回值
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/4/20 20:18
     */
    private int fetchAllToClientMcQuotaData(Object object) throws Exception {

        String mcNo;
        String mchntNo;
        String ruleIndex;
        int batchStatus;
        String mcStartDate;
        String sponsor = "";
        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);
        String lastSecondDate = DateUtil.getBaseDateOffsetDay(lastDate, CommonConstant.MINUS_ONE);
        String mcType;
        if (object instanceof MoneyOffAmountData) {
            mcNo = ((MoneyOffAmountData) object).getMcNo();
            mchntNo = ((MoneyOffAmountData) object).getMchntNo();
            ruleIndex = ((MoneyOffAmountData) object).getRuleIndex();
            mcStartDate = ((MoneyOffAmountData) object).getMcStartDate();
            sponsor = ((MoneyOffAmountData) object).getSponsor();
            mcType = ((MoneyOffAmountData) object).getMcType();
        } else if (object instanceof McCouponTxnData) {
            mcNo = ((McCouponTxnData) object).getMcNo();
            mchntNo = ((McCouponTxnData) object).getMchntNo();
            ruleIndex = ((McCouponTxnData) object).getRuleIndex();
            mcStartDate = ((McCouponTxnData) object).getMcStartDate();
            sponsor = ((McCouponTxnData) object).getSponsor();
            mcType = ((McCouponTxnData) object).getMcType();
        } else {
            rglog.error("错误的对象类型<{}>", object.getClass());
            return CommonConstant.PROCESS_FAILED;
        }

        /* 查询对客户营销活动统计表数据 */
        TMStat2C tmStat2C = selectToClientMcLevelStatistics(globalInstId, mcNo, ruleIndex);
        if (null == tmStat2C) {
            rglog.info("机构<{}>的营销活动<{}>的规则<{}>对客户营销活动统计表数据查询失败!", globalInstId, mcNo, ruleIndex);

            tmStat2C = new TMStat2C();
            tmStat2C.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            tmStat2C.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);

        }

        String batchDate;
        //查询统计信息备份表批次信息 查询营销活动信息表的批量处理情况即可
        String statPrimaryKey = "Custom" + globalInstId + "_" + mcNo;
        TMStatBak tmStatBak = selectTMStatBakByStatPrimaryKey(globalInstId, mcType, statPrimaryKey);
        //批次表为空，从来没执行过批量任务
        if (null == tmStatBak) {
            //从来没执行过批量任务，则从活动开始的第一天开始取数据
            batchDate = mcStartDate;
        } else {
            batchDate = DateUtil.getBaseDateOffsetDay(tmStatBak.getBatchDate(), 1);
        }
        //批量处理的日期小于昨天的日期，则需要取之前的数据
        while (DateUtil.compareDate(batchDate, lastDate) <= 0) {
            //获取的数据累加到活动统计中
            TMStat2CDay tmStat2CDayNew = selectToClientMcDayStatistics(globalInstId, mcNo, ruleIndex, batchDate);
            if (null == tmStat2CDayNew) {
                rglog.error("查询用户<{}>活动<{}>对客活动单日统计表 数据查询失败!", mcNo);
                tmStat2CDayNew = new TMStat2CDay();
                tmStat2CDayNew.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
                tmStat2CDayNew.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            }
            copytmStat2CData(tmStat2C, tmStat2CDayNew);
            //将批次日期加一天继续判断
            batchDate = DateUtil.getBaseDateOffsetDay(batchDate, 1);
        }
        /* 查询对客户营销活动单日统计表数据 */
        TMStat2CDay tmStat2CDay = selectToClientMcDayStatistics(globalInstId, mcNo, ruleIndex, globalTxnDate);
        if (null == tmStat2CDay) {
            rglog.info("机构<{}>的营销活动<{}>的规则<{}>对客户营销活动单日统计表数据查询失败!", globalInstId, mcNo, ruleIndex);
            /* 取到0条数据,说明该营销活动还未产生统计值,按所有统计值都是0进行处理 */
            tmStat2CDay = new TMStat2CDay();
            tmStat2CDay.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            tmStat2CDay.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);
        }

        /* 对象赋值 */
        if (object instanceof MoneyOffAmountData || object instanceof McCouponTxnData) {
            copyMoneyOffToClientStatData(tmStat2C, object);
            copyMoneyOffToClientSingleDayStatData(tmStat2CDay, object);
        } else {
            rglog.error("错误的对象类型<{}>", object.getClass().getClass());
            return CommonConstant.PROCESS_FAILED;
        }

        //不是银行全资的 需要获取商户统计信息
        if (!CommonConstant.SPONSOR_BANK.equals(sponsor)) {
            /* 查询对客户营销活动商户统计表数据 */
            TMStat2CMchnt tmStat2CMchnt = selectToClientMcMchntStatistics(globalInstId, mcNo, mchntNo);
            if (null == tmStat2CMchnt) {
                rglog.info("机构<{}>的商户<{}>的减免类营销活动<{}>的对客户营销活动商户统计表数据查询失败!", globalInstId, mchntNo, mcNo);
                /* 取到0条数据,说明该营销活动还未产生统计值,按所有统计值都是0进行处理 */
                tmStat2CMchnt = new TMStat2CMchnt();
                tmStat2CMchnt.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
                tmStat2CMchnt.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);

            }
            statPrimaryKey = "MchntStat" + globalInstId + "_" + mcNo;
            tmStatBak = selectTMStatBakByStatPrimaryKey(globalInstId, mcType, statPrimaryKey);
            //批次表为空，从来没执行过批量任务
            if (null == tmStatBak) {
                //从来没执行过批量任务，则从活动开始的第一天开始取数据
                batchDate = mcStartDate;
            } else {
                batchDate = DateUtil.getBaseDateOffsetDay(tmStatBak.getBatchDate(), 1);
            }
            //批量处理的日期小于昨天的日期，则需要取之前的数据
            while (DateUtil.compareDate(batchDate, lastDate) <= 0) {
                //获取的数据累加到活动统计中
                TMStat2CMchntDay tmStat2CMchntDay = selectToClientMcMchntDayStatistics(globalInstId, mcNo, mchntNo, batchDate);
                if (null == tmStat2CMchntDay) {
                    rglog.error("查询营销活动<{}>对客活动单日统计表 数据查询失败!", mcNo);
                    tmStat2CMchntDay = new TMStat2CMchntDay();
                    tmStat2CMchntDay.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
                    tmStat2CMchntDay.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);
                }
                copytmStat2CMchntData(tmStat2CMchnt, tmStat2CMchntDay);
                //将批次日期加一天继续判断
                batchDate = DateUtil.getBaseDateOffsetDay(batchDate, 1);
            }

            /* 查询对客户营销活动商户单日统计表数据 */
            TMStat2CMchntDay tmStat2CMchntDay = selectToClientMcMchntDayStatistics(globalInstId, mcNo, mchntNo, globalTxnDate);
            if (null == tmStat2CMchntDay) {
                rglog.info("机构<{}>的商户<{}>的减免类营销活动<{}>的对客户营销活动商户统计表数据查询失败!", globalInstId, mchntNo, mcNo);
                /* 取到0条数据,说明该营销活动还未产生统计值,按所有统计值都是0进行处理 */
                tmStat2CMchntDay = new TMStat2CMchntDay();
                tmStat2CMchntDay.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
                tmStat2CMchntDay.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            }

            /* 对象赋值 */
            if (object instanceof MoneyOffAmountData || object instanceof McCouponTxnData) {
                copyMoneyOffToClientMchntStatData(tmStat2CMchnt, object);
                copyMoneyOffToClientMchntDayStatData(tmStat2CMchntDay, object);
            } else {
                rglog.error("错误的对象类型<{}>", object.getClass().getClass());
                return CommonConstant.PROCESS_FAILED;
            }
        }

        return CommonConstant.PROCESS_SUCCESS;
    }

    /**
     * 查询对客户营销活动统计表数据
     *
     * @param instId    法人机构号
     * @param mcNo      营销活动编号
     * @param ruleIndex 规则顺序号
     * @return cc.rengu.igas.momp.common.entity.TMStat2C 对客户营销活动统计表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/4/14 22:47
     */
    private TMStat2C selectToClientMcLevelStatistics(String instId, String mcNo, String ruleIndex) throws Exception {

        TMStat2C tmStat2C = new TMStat2C();
        tmStat2C.setInstId(instId);
        tmStat2C.setMcNo(mcNo);
        tmStat2C.setRuleIndex(ruleIndex);

        TMStat2CMapper tmStat2CMapper = new TMStat2CMapperImpl();
        return tmStat2CMapper.selectToClientMcLevelStatistics(tmStat2C);
    }

    /**
     * 查询对客户营销活动商户统计表数据
     *
     * @param instId  法人机构号
     * @param mcNo    营销活动编号
     * @param mchntNo 商户编号
     * @return cc.rengu.igas.momp.common.entity.TMStat2CMchnt 对客户营销活动商户统计表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/4/15 15:38
     */
    private TMStat2CMchnt selectToClientMcMchntStatistics(String instId, String mcNo, String mchntNo) throws Exception {

        TMStat2CMchnt tmStat2CMchnt = new TMStat2CMchnt();
        tmStat2CMchnt.setInstId(instId);
        tmStat2CMchnt.setMcNo(mcNo);
        tmStat2CMchnt.setMchntNo(mchntNo);

        TMStat2CMchntMapper tmStat2CMchntMapper = new TMStat2CMchntMapperImpl();
        return tmStat2CMchntMapper.selectToClientMcMchntStatistics(tmStat2CMchnt);
    }

    /**
     * 查询对客户营销活动商户单日统计表数据
     *
     * @param instId  法人机构号
     * @param mcNo    营销活动编号
     * @param mchntNo 商户编号
     * @return cc.rengu.igas.momp.common.entity.TMStat2CMchntDay 对客户营销活动商户单日统计表
     * @throws Exception 异常信息
     * @author Jinan Liu
     * @since 2020/4/15 17:11
     */
    private TMStat2CMchntDay selectToClientMcMchntDayStatistics(String instId, String mcNo, String mchntNo, String txnDate) throws Exception {

        TMStat2CMchntDay tmStat2CMchntDay = new TMStat2CMchntDay();
        tmStat2CMchntDay.setInstId(instId);
        tmStat2CMchntDay.setMcNo(mcNo);
        tmStat2CMchntDay.setMchntNo(mchntNo);
        tmStat2CMchntDay.setTxnDate(txnDate);

        TMStat2CMchntDayMapper tmStat2CMchntDayMapper = new TMStat2CMchntDayMapperImpl();
        return tmStat2CMchntDayMapper.selectToClientMcMchntDayStatistics(tmStat2CMchntDay);
    }

    /**
     * 对客类营销活动统计数据赋值
     *
     * @param tmStat2C 对客户营销活动统计表
     * @param object   营销活动金额数据
     * @author Jinan Liu
     * @since 2020/4/18 21:54
     */
    private void copyMoneyOffToClientStatData(TMStat2C tmStat2C, Object object) {
        if (object instanceof MoneyOffAmountData) {
            /* 营销活动累计-总预算累计消耗笔数 */
            ((MoneyOffAmountData) object).setMcTotalQtyAcc(tmStat2C.getTotalQtyAcc());
            /* 营销活动累计-总预算累计消耗金额 */
            ((MoneyOffAmountData) object).setMcTotalAmtAcc(tmStat2C.getTotalAmtAcc());
        } else {
            /* 营销活动累计-总预算累计消耗笔数 */
            ((McCouponTxnData) object).setMcTotalQtyAcc(tmStat2C.getTotalQtyAcc());
            /* 营销活动累计-总预算累计消耗金额 */
            ((McCouponTxnData) object).setMcTotalAmtAcc(tmStat2C.getTotalAmtAcc());
        }
    }

    /**
     * 对客类营销活动单日统计数据赋值
     *
     * @param tmStat2CDay 对客户营销活动单日统计表
     * @param object      营销活动金额数据
     * @author Jinan Liu
     * @since 2020/4/18 21:54
     */
    private void copyMoneyOffToClientSingleDayStatData(TMStat2CDay tmStat2CDay, Object object) {

        if (object instanceof MoneyOffAmountData) {
            /* 营销活动单日累计-总预算累计消耗笔数 */
            ((MoneyOffAmountData) object).setDayTotalQtyAcc(tmStat2CDay.getTotalQtyAcc());
            /* 营销活动单日累计-总预算累计消耗金额 */
            ((MoneyOffAmountData) object).setDayTotalAmtAcc(tmStat2CDay.getTotalAmtAcc());
        } else {
            /* 营销活动单日累计-总预算累计消耗笔数 */
            ((McCouponTxnData) object).setDayTotalQtyAcc(tmStat2CDay.getTotalQtyAcc());
            /* 营销活动单日累计-总预算累计消耗金额 */
            ((McCouponTxnData) object).setDayTotalAmtAcc(tmStat2CDay.getTotalAmtAcc());
        }
    }

    /**
     * 对客户营销活动商户统计数据赋值
     *
     * @param tmStat2CMchnt 对客户营销活动商户统计表
     * @param object        操作对象
     * @author Jinan Liu
     * @since 2020/4/18 21:55
     */
    private void copyMoneyOffToClientMchntStatData(TMStat2CMchnt tmStat2CMchnt, Object object) {

        if (object instanceof MoneyOffAmountData) {
            /* 营销活动单日累计-总预算累计消耗笔数 */
            ((MoneyOffAmountData) object).setMchntTotalQtyAcc(tmStat2CMchnt.getTotalQtyAcc());
            /* 营销活动单日累计-总预算累计消耗金额 */
            ((MoneyOffAmountData) object).setMchntTotalAmtAcc(tmStat2CMchnt.getTotalAmtAcc());
        } else {
            /* 营销活动单日累计-总预算累计消耗笔数 */
            ((McCouponTxnData) object).setMchntTotalQtyAcc(tmStat2CMchnt.getTotalQtyAcc());
            /* 营销活动单日累计-总预算累计消耗金额 */
            ((McCouponTxnData) object).setMchntTotalAmtAcc(tmStat2CMchnt.getTotalAmtAcc());
        }
    }

    /**
     * 对客户营销活动商户单日统计数据赋值
     *
     * @param tmStat2CMchntDay 对客户营销活动商户单日统计表
     * @param object           操作对象
     * @author Jinan Liu
     * @since 2020/4/18 21:54
     */
    private void copyMoneyOffToClientMchntDayStatData(TMStat2CMchntDay tmStat2CMchntDay, Object object) {

        if (object instanceof MoneyOffAmountData) {
            /* 营销活动单日累计-累计优惠笔数 */
            ((MoneyOffAmountData) object).setMchntDayTotalQtyAcc(tmStat2CMchntDay.getTotalQtyAcc());
            /* 营销活动单日累计-累计优惠金额 */
            ((MoneyOffAmountData) object).setMchntDayTotalAmtAcc(tmStat2CMchntDay.getTotalAmtAcc());
        } else {
            /* 营销活动单日累计-累计优惠笔数 */
            ((McCouponTxnData) object).setMchntDayTotalQtyAcc(tmStat2CMchntDay.getTotalQtyAcc());
            /* 营销活动单日累计-累计优惠金额 */
            ((McCouponTxnData) object).setMchntDayTotalAmtAcc(tmStat2CMchntDay.getTotalAmtAcc());
        }
    }

    /**
     * 检查所有额度和限额控制
     *
     * @param tmMcMoneyOffInfo   减免类营销活动信息表
     * @param moneyOffAmountData 减免类营销活动金额数据
     * @return int 返回码
     * @author Jinan Liu
     * @since 2020/4/18 22:09
     */
    private int checkAllQuotaWithMcType(TMMcMoneyOffInfo tmMcMoneyOffInfo, MoneyOffAmountData moneyOffAmountData) {

        String mcType = tmMcMoneyOffInfo.getMcType();

        if (!StringUtil.isNullorEmpty(mcType)) {
            switch (McTypeEnum.getByValue(mcType)) {
                case REDUCTION_FIXED_AMOUNT:
                    /* 满额立减固定金额 */
                    return checkReductionFixedAmountLimits(tmMcMoneyOffInfo, moneyOffAmountData);
                case REDUCTION_RANDOM_AMOUNT:
                    /* 满额立减随机金额 */
                case REDUCTION_FIXED_RATE:
                    /* 满额固定折扣 */
                case REDUCTION_RANDOM_RATE:
                    /* 满额随机折扣 */
                    return checkReductionRandomRateLimits(tmMcMoneyOffInfo, moneyOffAmountData);
                default:
                    /* 其他类型营销活动 */
                    return CommonConstant.PROCESS_FAILED;
            }
        } else {
            return CommonConstant.PROCESS_FAILED;
        }
    }

    /**
     * 满额立减固定金额类减免营销活动交易限额处理
     *
     * @param tmMcMoneyOffInfo   减免类营销活动信息表
     * @param moneyOffAmountData 减免类营销活动金额数据
     * @return int 返回码
     * @author Jinan Liu
     * @since 2020/4/15 14:27
     */
    private int checkReductionFixedAmountLimits(TMMcMoneyOffInfo tmMcMoneyOffInfo, MoneyOffAmountData moneyOffAmountData) {

        /* 当前优惠金额 */
        BigDecimal totalSubsidy = new BigDecimal(moneyOffAmountData.getTotalSubsidy()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        /* 规则信息-顺序号 */
        String ruleIndex = moneyOffAmountData.getRuleIndex();
        /* 规则信息-总优惠数量 */
        BigDecimal ruleDiscountQuantity = new BigDecimal(moneyOffAmountData.getDiscountQuantity()).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);
        /* 规则信息-单日消耗预算 */
        BigDecimal dayQtyLimit = new BigDecimal(moneyOffAmountData.getBudgetDayLimit()).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);

        /* 当前累计历史优惠笔数 */
        BigDecimal mcTotalDiscountQty = new BigDecimal(moneyOffAmountData.getMcTotalQtyAcc());
        /* 当前当日累计优惠笔数 */
        BigDecimal dayTotalDiscountQty = new BigDecimal(moneyOffAmountData.getDayTotalQtyAcc());
        /* 当前总累计优惠笔数 */
        BigDecimal totalDiscountQty = mcTotalDiscountQty.add(dayTotalDiscountQty).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);

        rglog.info("当前已累计优惠笔数<{}> 规则最大优惠笔数<{}>；当前当日已累计优惠笔数<{}> 单日最大优惠笔数<{}>!", totalDiscountQty.toString(), ruleDiscountQuantity,
                dayTotalDiscountQty.toString(), dayQtyLimit.toString());

        /* 检查指定规则层面优惠笔数是否超出 */
        if (CommonConstant.ZERO < totalDiscountQty.add(BigDecimal.ONE).compareTo(ruleDiscountQuantity)) {
            rglog.info("当前已累计优惠笔数<{}>已超出对应规则<{}>最大优惠笔数<{}>,不予优惠!", totalDiscountQty.toString(), ruleIndex, ruleDiscountQuantity.toString());
            return CommonConstant.PROCESS_FAILED;
        }

        /* 检查指定规则层面单日优惠笔数是否超出 */
        if (CommonConstant.ZERO < dayTotalDiscountQty.add(BigDecimal.ONE).compareTo(dayQtyLimit)) {
            rglog.info("当前单日已累计优惠笔数<{}>已超出对应规则<{}>最大单日优惠笔数<{}>,不予优惠!", dayTotalDiscountQty.toString(), ruleIndex, dayQtyLimit.toString());
            return CommonConstant.PROCESS_FAILED;
        }

        /* 如果是银商联合的活动  检查指定规则层面单日优惠笔数是否超出 */
        if (CommonConstant.SPONSOR_MIXED.equals(tmMcMoneyOffInfo.getSponsor())) {
            BigDecimal mchntSubsidy = new BigDecimal(moneyOffAmountData.getMchntSubsidy()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 每商户最大优惠金额 */
            BigDecimal mchntDiscountLimitAmt = new BigDecimal(moneyOffAmountData.getMchntDiscountLimitAmt()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户历史累计优惠金额 */
            BigDecimal mchntTotalAmtAcc = new BigDecimal(moneyOffAmountData.getMchntTotalAmtAcc()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户当日累计优惠金额 */
            BigDecimal mchntDayTotalAmtAcc = new BigDecimal(moneyOffAmountData.getMchntDayTotalAmtAcc()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户截止到当前交易前累计优惠金额 */
            BigDecimal mchntCurrentTotalAmtAcc = mchntTotalAmtAcc.add(mchntDayTotalAmtAcc).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

            /* 联合营销判断商户剩余可优惠额度 */
            if (CommonConstant.ZERO < mchntCurrentTotalAmtAcc.compareTo(mchntDiscountLimitAmt)) {
                /* 若当前商户累计交易金额大于商户最大优惠金额,流程结束,不予优惠 */
                rglog.info("当前商户已累计优惠金额<{}>已超过商户最大优惠金额<{}>,不予优惠!", mchntCurrentTotalAmtAcc.toString(), mchntDiscountLimitAmt.toString());
                return CommonConstant.PROCESS_FAILED;
            } else {
                /* 若当前商户累计交易金额不大于商户最大优惠金额,但当前商户累计交易金额加本笔交易计算的优惠额大于商户最大优惠金额,则不予优惠 */
                if (CommonConstant.ZERO < mchntCurrentTotalAmtAcc.add(mchntSubsidy).compareTo(mchntDiscountLimitAmt)) {
                    rglog.info("当前商户累计优惠金额(加本笔即将优惠的金额)<{}>已超过商户最大优惠金额<{}>,不予优惠!", mchntCurrentTotalAmtAcc.add(mchntSubsidy).toString(), mchntDiscountLimitAmt.toString());
                    return CommonConstant.PROCESS_FAILED;
                }
            }
        }

        moneyOffAmountData.setTotalSubsidy(totalSubsidy.toString());

        McSubsidyData mcSubsidyData = new McSubsidyData();
        mcSubsidyData.setTotalSubsidy(totalSubsidy.toString());
        mcSubsidyData.setSponsor(tmMcMoneyOffInfo.getSponsor());
        if (CommonConstant.SPONSOR_MIXED.equals(tmMcMoneyOffInfo.getSponsor())) {
            mcSubsidyData.setBudget(tmMcMoneyOffInfo.getBudget());
            mcSubsidyData.setBankBudget(tmMcMoneyOffInfo.getBankBudget());
            mcSubsidyData.setExpectMchntQty(tmMcMoneyOffInfo.getExpectMchntQty());
            mcSubsidyData.setBankBudgetRatio(tmMcMoneyOffInfo.getBankBudgetRatio());
        }
        mcSubsidyData.setMcType(tmMcMoneyOffInfo.getMcType());

        /* 计算银行和商户出资比例 */
        int retCode = calculateBankAndMchntSubsidyRatio(mcSubsidyData);
        if (CommonConstant.PROCESS_SUCCESS != retCode) {
            rglog.info("机构<{}>的营销活动<{}>计算银行补贴金额和商户补贴金额失败,本营销活动不予优惠!", tmMcMoneyOffInfo.getInstId(), tmMcMoneyOffInfo.getMcNo());
        } else {
            rglog.info("机构<{}>的营销活动<{}>当前总优惠金额<{}>,银行优惠金额<{}>,商户优惠金额<{}>!", tmMcMoneyOffInfo.getInstId(), tmMcMoneyOffInfo.getMcNo(),
                    moneyOffAmountData.getTotalSubsidy(), moneyOffAmountData.getBankSubsidy(), moneyOffAmountData.getMchntSubsidy());

            moneyOffAmountData.setBankSubsidy(mcSubsidyData.getBankSubsidy());
            moneyOffAmountData.setMchntSubsidy(mcSubsidyData.getMchntSubsidy());
            if (CommonConstant.SPONSOR_MIXED.equals(tmMcMoneyOffInfo.getSponsor())) {
                moneyOffAmountData.setBankDiscountLimitAmt(mcSubsidyData.getBankDiscountLimitAmt());
                moneyOffAmountData.setMchntDiscountLimitAmt(mcSubsidyData.getMchntDiscountLimitAmt());
            }
        }

        return retCode;
    }

    /**
     * 满额满额立减随机金额类\满额固定折扣类\满额随机折扣类减免营销活动交易限额处理
     *
     * @param tmMcMoneyOffInfo   减免类营销活动信息表
     * @param moneyOffAmountData 减免类营销活动金额数据
     * @return int 返回码
     * @author Jinan Liu
     * @since 2020/4/15 17:43
     */
    private int checkReductionRandomRateLimits(TMMcMoneyOffInfo tmMcMoneyOffInfo, MoneyOffAmountData moneyOffAmountData) {

        /* 当前优惠金额 */
        BigDecimal totalSubsidy = new BigDecimal(moneyOffAmountData.getTotalSubsidy()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        /* 规则信息-顺序号 */
        String ruleIndex = moneyOffAmountData.getRuleIndex();
        /* 规则信息-单次优惠限制 */
        BigDecimal discountLimit = new BigDecimal(moneyOffAmountData.getDiscountLimit()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
        /* 规则信息-优惠总预算 */
        BigDecimal budget = new BigDecimal(moneyOffAmountData.getRuleBudget()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
        /* 规则信息-单日消耗预算 */
        BigDecimal dayQtyLimit = new BigDecimal(moneyOffAmountData.getBudgetDayLimit()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        /* 判断营销活动类型 */
        if (CommonConstant.IS_EQUAL_TO != discountLimit.compareTo(BigDecimal.ZERO.setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP))) {
            /* 满额固定折扣或满额随机折扣,需要检查单次优惠限额 */
            if (CommonConstant.ZERO <= totalSubsidy.compareTo(discountLimit)) {
                /* 减免金额已超过减免规则对应单次优惠上限,最高只可优惠单次优惠限额的金额 */
                rglog.error("减免金额<{}>超过减免规则对应单次优惠上限<{}>,最高只可优惠单次优惠限额的金额<{}>", totalSubsidy, discountLimit, discountLimit);
                totalSubsidy = discountLimit;
            }
        } else {
            /* 满额立减随机金额,无须检查单次优惠限制 */
            rglog.info("满额立减随机金额,无须检查单次优惠限制!");
        }


        /* 当前累计历史优惠金额-优惠前 */
        BigDecimal mcTotalDiscountAmt = new BigDecimal(moneyOffAmountData.getMcTotalAmtAcc());
        /* 当前当日累计优惠金额-优惠前 */
        BigDecimal dayTotalDiscountAmt = new BigDecimal(moneyOffAmountData.getDayTotalAmtAcc());
        /* 当前总累计优惠金额-优惠后 */
        BigDecimal totalDiscountAmt = totalSubsidy.add(mcTotalDiscountAmt).add(dayTotalDiscountAmt).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
        /* 当前单日累计优惠金额-优惠后 */
        BigDecimal totalDayDiscountAmt = totalSubsidy.add(dayTotalDiscountAmt).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

        /* 检查指定规则层面优惠金额是否超出 */
        if (CommonConstant.ZERO <= mcTotalDiscountAmt.add(dayTotalDiscountAmt).compareTo(budget)) {
            /* 当前累计历史优惠金额+当前当日累计优惠金额>=规则优惠额度,不可优惠 */
            rglog.info("当前优惠前累计优惠金额<{}>已超出对应规则<{}>最大优惠金额<{}>,不予优惠!", mcTotalDiscountAmt.add(dayTotalDiscountAmt).toString(), ruleIndex, budget.toString());
            return CommonConstant.PROCESS_FAILED;
        } else {
            if (CommonConstant.ZERO < totalDiscountAmt.compareTo(budget)) {
                /* 当前累计历史优惠金额+当前当日累计优惠金额+本次优惠金额>规则优惠额度,仅可优惠规则优惠额度-(当前累计历史优惠金额+当前当日累计优惠金额)部分金额 */
                totalSubsidy = budget.subtract(mcTotalDiscountAmt).subtract(dayTotalDiscountAmt).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                rglog.info("当前优惠后累计优惠金额<{}>已超出对应规则<{}>最大优惠金额<{}>,仅可优惠<{}>!", totalDiscountAmt.toString(), ruleIndex, budget.toString(), totalSubsidy);
                //判断优惠下限金额是否大于优惠金额
                if (!StringUtil.isNullorEmpty(moneyOffAmountData.getFloorAmt())) {
                    if (CommonConstant.ZERO > totalSubsidy.compareTo(new BigDecimal(moneyOffAmountData.getFloorAmt()))) {
                        rglog.info("优惠金额<{}>小于优惠下限金额<{}>,不予优惠", totalSubsidy, moneyOffAmountData.getFloorAmt());
                        return CommonConstant.PROCESS_FAILED;
                    }
                }
                if (tmMcMoneyOffInfo.getMcType().equals(McTypeEnum.REDUCTION_FIXED_RATE.getMcTypeCode())) {
                    rglog.info("活动类型为固定折扣，优惠金额<{}>小于固定折扣所优惠的金额,不予优惠", totalSubsidy);
                    return CommonConstant.PROCESS_FAILED;
                }
            } else {
                /* 当前累计历史优惠金额+当前当日累计优惠金额+本次优惠金额<=规则优惠额度,正常优惠 */
                rglog.info("当前优惠后累计优惠金额<{}>未超出对应规则<{}>最大优惠金额<{}>,正常优惠!", totalDiscountAmt.toString(), ruleIndex, budget.toString());
            }
        }

        /* 检查指定规则层面单日优惠金额是否超出 */
        if (CommonConstant.ZERO <= dayTotalDiscountAmt.compareTo(dayQtyLimit)) {
            /* 当前累计单日优惠金额>=规则单日优惠额度,不可优惠 */
            rglog.info("当前优惠前单日累计优惠金额<{}>已超出对应规则<{}>最大单日优惠金额<{}>,不予优惠!", dayTotalDiscountAmt.toString(), ruleIndex, dayQtyLimit.toString());
            return CommonConstant.PROCESS_FAILED;
        } else {
            if (CommonConstant.ZERO < totalDayDiscountAmt.compareTo(dayQtyLimit)) {
                /* 当前单日累计优惠金额+本次优惠金额>=规则优惠额度,仅可优惠规则优惠额度-当前当日累计优惠金额部分金额 */
                totalSubsidy = dayQtyLimit.subtract(dayTotalDiscountAmt).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                rglog.info("当前优惠后单日累计优惠金额<{}>已超出对应规则<{}>最大优惠金额<{}>,仅可优惠<{}>!", totalDayDiscountAmt.toString(), ruleIndex, dayQtyLimit.toString(), totalSubsidy);
                //判断优惠下限金额是否大于优惠金额
                if (!StringUtil.isNullorEmpty(moneyOffAmountData.getFloorAmt())) {
                    if (CommonConstant.ZERO > totalSubsidy.compareTo(new BigDecimal(moneyOffAmountData.getFloorAmt()))) {
                        rglog.info("优惠金额<{}>小于优惠下限金额<{}>,不予优惠", totalSubsidy, moneyOffAmountData.getFloorAmt());
                        return CommonConstant.PROCESS_FAILED;
                    }
                }
                if (tmMcMoneyOffInfo.getMcType().equals(McTypeEnum.REDUCTION_FIXED_RATE.getMcTypeCode())) {
                    rglog.info("活动类型为固定折扣，优惠金额<{}>小于固定折扣所优惠的金额,不予优惠", totalSubsidy);
                    return CommonConstant.PROCESS_FAILED;
                }
            } else {
                /* 当前当日累计优惠金额+本次优惠金额<=规则单日优惠额度,正常优惠 */
                rglog.debug("当前优惠后累计优惠金额<{}>未超出对应规则<{}>最大优惠金额<{}>,正常优惠!", totalDiscountAmt.toString(), ruleIndex, budget.toString());
            }
        }

        /* 本类营销活动预算是固定的,后面添加金额校验,目前暂不校验 */

        /* 检查指定规则层面单日优惠笔数是否超出 */
        if (CommonConstant.SPONSOR_MIXED.equals(tmMcMoneyOffInfo.getSponsor())) {
            BigDecimal mchntSubsidy = new BigDecimal(moneyOffAmountData.getMchntSubsidy()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 每商户最大优惠金额 */
            BigDecimal mchntDiscountLimitAmt = new BigDecimal(moneyOffAmountData.getMchntDiscountLimitAmt()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户历史累计优惠金额 */
            BigDecimal mchntTotalAmtAcc = new BigDecimal(moneyOffAmountData.getMchntTotalAmtAcc()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户当日累计优惠金额 */
            BigDecimal mchntDayTotalAmtAcc = new BigDecimal(moneyOffAmountData.getMchntDayTotalAmtAcc()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户截止到当前交易前累计优惠金额 */
            BigDecimal mchntCurrentTotalAmtAcc = mchntTotalAmtAcc.add(mchntDayTotalAmtAcc).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            //商户剩余可优惠额度
            BigDecimal mchntSurplusDiscountAmt = mchntDiscountLimitAmt.subtract(mchntCurrentTotalAmtAcc).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            //
            BigDecimal ratio = new BigDecimal("1");
            //银行出资比例
            BigDecimal bankRatio = new BigDecimal(tmMcMoneyOffInfo.getBankBudgetRatio());

            /* 联合营销判断商户剩余可优惠额度 */
            if (CommonConstant.ZERO < mchntCurrentTotalAmtAcc.compareTo(mchntDiscountLimitAmt)) {
                /* 若当前商户累计交易金额大于商户最大优惠金额,流程结束,不予优惠 */
                rglog.info("当前商户累计优惠金额<{}>已超过商户最大优惠金额<{}>,不予优惠!", mchntCurrentTotalAmtAcc.toString(), mchntDiscountLimitAmt.toString());
                return CommonConstant.PROCESS_FAILED;
            } else {
                /* 若当前商户累计交易金额不大于商户最大优惠金额,但当前商户累计交易金额加本笔交易计算的优惠额大于商户最大优惠金额,则仅优惠可优惠金额 */
                if (CommonConstant.ZERO < mchntCurrentTotalAmtAcc.add(mchntSubsidy).compareTo(mchntDiscountLimitAmt) && CommonConstant.ZERO > mchntCurrentTotalAmtAcc.compareTo(mchntDiscountLimitAmt)) {
                    //根据商户可优惠额度算出的减免类总优惠金额
                    BigDecimal mchntTotalAmt = mchntSurplusDiscountAmt.divide(ratio.subtract(bankRatio), CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
                    //根据商户可优惠额度算出的减免类总优惠金额应大于等于优惠下限  固定折扣类不判断优惠下限
                    if (!StringUtil.isNullorEmpty(moneyOffAmountData.getFloorAmt())) {
                        if (CommonConstant.ZERO <= mchntTotalAmt.compareTo(new BigDecimal(moneyOffAmountData.getFloorAmt()))) {
                            rglog.info("根据商户剩余可优惠额度算出的减免类总优惠金额<{}>大于等于优惠下限<{}>,可优惠", mchntTotalAmt, new BigDecimal(moneyOffAmountData.getFloorAmt()));
                            totalSubsidy = mchntTotalAmt;
                        } else {
                            rglog.info("根据商户剩余可优惠额度算出的减免类总优惠金额<{}>小于优惠下限<{}>，不予优惠", mchntTotalAmt, new BigDecimal(moneyOffAmountData.getFloorAmt()));
                            return CommonConstant.PROCESS_FAILED;
                        }
                    }
                } else if (CommonConstant.ZERO >= mchntCurrentTotalAmtAcc.add(mchntSubsidy).compareTo(mchntDiscountLimitAmt)) {
                    rglog.info("当前商户累计优惠金额<{}>未超过银商联合活动每商户最大优惠金额<{}>,继续流程!", mchntCurrentTotalAmtAcc.add(mchntSubsidy).toString(), mchntDiscountLimitAmt.toString());

                } else {
                    rglog.info("当前商户累计优惠金额<{}>已超过银商联合活动每商户最大优惠金额<{}>,不予优惠!", mchntCurrentTotalAmtAcc.add(mchntSubsidy).toString(), mchntDiscountLimitAmt.toString());
                    return CommonConstant.PROCESS_FAILED;
                }
            }
        }

        moneyOffAmountData.setTotalSubsidy(totalSubsidy.toString());

        McSubsidyData mcSubsidyData = new McSubsidyData();
        mcSubsidyData.setTotalSubsidy(totalSubsidy.toString());
        mcSubsidyData.setSponsor(tmMcMoneyOffInfo.getSponsor());
        if (CommonConstant.SPONSOR_MIXED.equals(tmMcMoneyOffInfo.getSponsor())) {
            mcSubsidyData.setBudget(tmMcMoneyOffInfo.getBudget());
            mcSubsidyData.setBankBudget(tmMcMoneyOffInfo.getBankBudget());
            mcSubsidyData.setExpectMchntQty(tmMcMoneyOffInfo.getExpectMchntQty());
            mcSubsidyData.setBankBudgetRatio(tmMcMoneyOffInfo.getBankBudgetRatio());
        }
        mcSubsidyData.setMcType(tmMcMoneyOffInfo.getMcType());

        /* 计算银行和商户出资比例 */
        int retCode = calculateBankAndMchntSubsidyRatio(mcSubsidyData);
        if (CommonConstant.PROCESS_SUCCESS != retCode) {
            rglog.info("机构<{}>的营销活动<{}>计算银行补贴金额和商户补贴金额失败,本营销活动不予优惠!", tmMcMoneyOffInfo.getInstId(), tmMcMoneyOffInfo.getMcNo());
        } else {
            rglog.info("机构<{}>的营销活动<{}>当前总优惠金额<{}>,银行优惠金额<{}>,商户优惠金额<{}>!", tmMcMoneyOffInfo.getInstId(), tmMcMoneyOffInfo.getMcNo(),
                    moneyOffAmountData.getTotalSubsidy(), moneyOffAmountData.getBankSubsidy(), moneyOffAmountData.getMchntSubsidy());

            moneyOffAmountData.setBankSubsidy(mcSubsidyData.getBankSubsidy());
            moneyOffAmountData.setMchntSubsidy(mcSubsidyData.getMchntSubsidy());
            if (CommonConstant.SPONSOR_MIXED.equals(tmMcMoneyOffInfo.getSponsor())) {
                moneyOffAmountData.setBankDiscountLimitAmt(mcSubsidyData.getBankDiscountLimitAmt());
                moneyOffAmountData.setMchntDiscountLimitAmt(mcSubsidyData.getMchntDiscountLimitAmt());
            }
        }

        return retCode;
    }

    /**
     * 减免信息数据库实体类和应答报文实体类转换
     *
     * @param tmMcMoneyOffInfo     减免类营销活动信息表
     * @param tmMcMoneyOffRuleInfo 减免类营销活动规则表
     * @return cc.rengu.igas.momp.facade.bean.PrePaymentAvailableMoneyOffMcInfoBean 减免类优惠信息对象
     * @author Jinan Liu
     * @since 2020/6/2 22:53
     */
    private PrePaymentAvailableMoneyOffMcInfoBean convertMoneyOffInfo(TMMcMoneyOffInfo tmMcMoneyOffInfo, TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo, McMoneyOffTxnData mcMoneyOffTxnData) {

        PrePaymentAvailableMoneyOffMcInfoBean prePaymentAvailableMoneyOffMcInfoBean = new PrePaymentAvailableMoneyOffMcInfoBean();

        /* 营销活动编号 */
        prePaymentAvailableMoneyOffMcInfoBean.setMcNo(tmMcMoneyOffInfo.getMcNo());
        /* 营销活动类型 */
        prePaymentAvailableMoneyOffMcInfoBean.setMcType(tmMcMoneyOffInfo.getMcType());
        /* 活动起始日期 */
        prePaymentAvailableMoneyOffMcInfoBean.setMcStartDate(tmMcMoneyOffInfo.getMcStartDate());
        /* 活动截止日期 */
        prePaymentAvailableMoneyOffMcInfoBean.setMcEndDate(tmMcMoneyOffInfo.getMcEndDate());
        /* 减免规则描述 */
        prePaymentAvailableMoneyOffMcInfoBean.setRuleContent(generateMoneyOffRuleContent(tmMcMoneyOffInfo.getMcType(), tmMcMoneyOffRuleInfo));
        if (tmMcMoneyOffInfo.getMcType().equals(McTypeEnum.REDUCTION_FIXED_AMOUNT.getMcTypeCode()) || tmMcMoneyOffInfo.getMcType().equals(McTypeEnum.REDUCTION_FIXED_RATE.getMcTypeCode())) {
            /* 减免规则优惠金额 */
            prePaymentAvailableMoneyOffMcInfoBean.setDiscountAmt(mcMoneyOffTxnData.getCellingAmt());
        } else {
            prePaymentAvailableMoneyOffMcInfoBean.setDiscountAmt(CommonConstant.ZERO_AMOUNT);
        }
        prePaymentAvailableMoneyOffMcInfoBean.setRuleIndex(tmMcMoneyOffRuleInfo.getRuleIndex());
        return prePaymentAvailableMoneyOffMcInfoBean;
    }

    /**
     * 根据减免规则信息生成减免规则信息描述
     *
     * @param tmMcMoneyOffRuleInfo 减免类营销活动规则表
     * @return java.lang.String 减免规则描述
     * @author Jinan Liu
     * @since 2020/6/2 22:57
     */
    private String generateMoneyOffRuleContent(String mcType, TMMcMoneyOffRuleInfo tmMcMoneyOffRuleInfo) {

        if (!StringUtil.isNullorEmpty(mcType)) {

            switch (McTypeEnum.getByValue(mcType)) {
                case REDUCTION_FIXED_AMOUNT:
                    return "满" + tmMcMoneyOffRuleInfo.getCriteria() + "减" + tmMcMoneyOffRuleInfo.getDiscountCelling() + "元";
                case REDUCTION_RANDOM_AMOUNT:
                    return "满" + tmMcMoneyOffRuleInfo.getCriteria() + "最低减" + tmMcMoneyOffRuleInfo.getDiscountFloor() + "元,最高减" + tmMcMoneyOffRuleInfo.getDiscountCelling() + "元";
                case REDUCTION_FIXED_RATE:
                    return "满" + tmMcMoneyOffRuleInfo.getCriteria() + "打" + tmMcMoneyOffRuleInfo.getDiscountCelling() + "折, 最高优惠" + tmMcMoneyOffRuleInfo.getDiscountLimit() + "元";
                case REDUCTION_RANDOM_RATE:
                    return "满" + tmMcMoneyOffRuleInfo.getCriteria() + "最低打" + tmMcMoneyOffRuleInfo.getDiscountFloor() + "折,最高打" + tmMcMoneyOffRuleInfo.getDiscountCelling() + "折, 最高优惠" + tmMcMoneyOffRuleInfo.getDiscountLimit() + "元";
                default:
                    return null;
            }

        } else {
            return null;
        }
    }

    /**
     * 报文检查及全局变量赋值
     *
     * @param queryAvailableDiscountInfoBeforePaymentRequest 支付前可优惠信息查询接口请求对象
     * @throws BizException 异常信息
     * @author Jinan Liu
     * @date 2020/7/23 18:11
     */
    private void messageValidation(QueryAvailableDiscountInfoBeforePaymentRequest queryAvailableDiscountInfoBeforePaymentRequest) throws BizException {

        /*交易金额	transAmt*/
        if (!StringUtil.isNullorEmpty(queryAvailableDiscountInfoBeforePaymentRequest.getTransAmt()) && new BigDecimal(queryAvailableDiscountInfoBeforePaymentRequest.getTransAmt()).compareTo(zero) < 0) {
            throw new BizException(RespCodeEnum.FIELD_HAS_NEGATIVE_NUMBER.getRespCode(), RespCodeEnum.FIELD_HAS_NEGATIVE_NUMBER.getRespDesc());
        }

        if (StringUtil.isNullorEmpty(queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getTransDate())) {
            rglog.error("交易日期必须上送!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        } else {
            globalTxnDate = queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getTransDate();
        }

        if (StringUtil.isNullorEmpty(queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getTransTime())) {
            rglog.error("交易时间必须上送!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        } else {
            globalTxnTime = queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getTransTime();
        }

        if (StringUtil.isNullorEmpty(queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getInstId())) {
            rglog.error("法人机构号必须上送!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        } else {
            globalInstId = queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getInstId();
        }

        if (StringUtil.isNullorEmpty(queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getTraceNo())) {
            rglog.error("流水号必须上送!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }

        if (StringUtil.isNullorEmpty(queryAvailableDiscountInfoBeforePaymentRequest.getMchntOrderId())) {
            rglog.error("需要上送商户订单号!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }

        if (null == queryAvailableDiscountInfoBeforePaymentRequest.getUserInfoBean()) {
            rglog.error("需要上送用户信息!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        if (null == queryAvailableDiscountInfoBeforePaymentRequest.getUserInfoBean().getUserIdList()) {
            rglog.error("需要上送用户信息!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        if (queryAvailableDiscountInfoBeforePaymentRequest.getUserInfoBean().getUserIdList().isEmpty()) {
            rglog.error("需要上送用户信息!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        discountId = "";
        for (int i = 0; i < queryAvailableDiscountInfoBeforePaymentRequest.getUserInfoBean().getUserIdList().size(); i++) {
            discountId = discountId + queryAvailableDiscountInfoBeforePaymentRequest.getUserInfoBean().getUserIdList().get(i) + ",";
        }
        rglog.info("上送userId<{}>", discountId);
        if (StringUtil.isNullorEmpty(queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getSrcSysId())) {
            rglog.error("需要上送源系统标识!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        } else {
            globalsSrcSysId = queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getSrcSysId();
        }

        if (StringUtil.isNullorEmpty(queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getTraceNo())) {
            rglog.error("需要上送流水号!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        } else {
            globalTraceNo = queryAvailableDiscountInfoBeforePaymentRequest.getHeader().getTraceNo();
        }

        /* 交易控制类赋值 */
        transactionResource = new TransactionResource();
        transactionResource.setInstId(globalInstId);
        transactionResource.setTxnNum(MompTxnNumEnum.AVAIL_DISCOUNT_PRE_QUERY.getTxnNum());

        globalTimeStamp = new SimpleDateFormat(CommonConstant.TIMESTAMP_FORMAT).format(new Date());

        tmTxnBizOpList = new ArrayList<>();
    }

    /**
     * 减免类活动业务操作流水表实体类列表数据转换
     *
     * @param prePaymentAvailableMoneyOffMcInfoBean 减免类优惠信息对象
     * @author Jinan Liu
     * @date 2020/8/19 10:53
     */
    private void createMoneyOffOprLog(PrePaymentAvailableMoneyOffMcInfoBean prePaymentAvailableMoneyOffMcInfoBean) {

        TMTxnBizOp tmTxnBizOp = new TMTxnBizOp();
        tmTxnBizOp.setInstId(globalInstId);
        tmTxnBizOp.setTxnDate(globalTxnDate);
        tmTxnBizOp.setTxnTime(globalTxnTime);
        tmTxnBizOp.setTxnNum(MompTxnNumEnum.AVAIL_DISCOUNT_PRE_QUERY.getTxnNum());
        tmTxnBizOp.setMsgSrcId(globalsSrcSysId);
        tmTxnBizOp.setSysSeqNum(globalTraceNo);
        tmTxnBizOp.setMcNo(prePaymentAvailableMoneyOffMcInfoBean.getMcNo());
        tmTxnBizOp.setBizOprType(QueryTypeEnum.USER_QYERY_TYPE.getQueryTypeCode());
        tmTxnBizOp.setBizOprId(globalUserId);
        tmTxnBizOp.setBizOprOrgId(CommonConstant.DEFAULT_ORG_ID);
        tmTxnBizOp.setBizOprRole(QueryRoleEnum.USER_QYERY_ROLE.getQueryRoleCode());
        tmTxnBizOp.setBizOprStatus("1");
        tmTxnBizOp.setOprId(CommonConstant.DEFAULT_OPR_ID);
        tmTxnBizOp.setCreateTime(globalTimeStamp);

        tmTxnBizOpList.add(tmTxnBizOp);
    }

    /**
     * 卡券类活动业务操作流水表实体类列表数据转换
     *
     * @param tmCouponInfo 卡券信息表
     * @author Jinan Liu
     * @date 2020/8/19 10:57
     */
    private void createCouponOprLog(TMCouponInfo tmCouponInfo) {

        TMTxnBizOp tmTxnBizOp = new TMTxnBizOp();
        tmTxnBizOp.setInstId(globalInstId);
        tmTxnBizOp.setTxnDate(globalTxnDate);
        tmTxnBizOp.setTxnTime(globalTxnTime);
        tmTxnBizOp.setTxnNum(MompTxnNumEnum.AVAIL_DISCOUNT_PRE_QUERY.getTxnNum());
        tmTxnBizOp.setMsgSrcId(globalsSrcSysId);
        tmTxnBizOp.setSysSeqNum(globalTraceNo);
        tmTxnBizOp.setMcNo(tmCouponInfo.getMcNo());
        tmTxnBizOp.setBizOprType(QueryTypeEnum.USER_QYERY_TYPE.getQueryTypeCode());
        tmTxnBizOp.setBizOprId(globalUserId);
        tmTxnBizOp.setBizOprOrgId(CommonConstant.DEFAULT_ORG_ID);
        tmTxnBizOp.setBizOprRole(QueryRoleEnum.USER_QYERY_ROLE.getQueryRoleCode());
        tmTxnBizOp.setBizOprStatus("1");
        tmTxnBizOp.setOprId(CommonConstant.DEFAULT_OPR_ID);
        tmTxnBizOp.setCreateTime(globalTimeStamp);

        tmTxnBizOpList.add(tmTxnBizOp);
    }

    /**
     * 检查 上送 订单明细表 金额字段不能为负数
     *
     * @param paymentOrderInfoBean
     * @author ls
     * @date 2020/10/21
     */
    private void checkOrderDetFieldHasNegativeNumber(PaymentOrderInfoBean paymentOrderInfoBean) {
        /*  订单金额	orderAmt*/
        if (!StringUtil.isNullorEmpty(paymentOrderInfoBean.getOrderAmt()) && new BigDecimal(paymentOrderInfoBean.getOrderAmt()).compareTo(zero) < 0) {
            throw new BizException(RespCodeEnum.FIELD_HAS_NEGATIVE_NUMBER.getRespCode(), RespCodeEnum.FIELD_HAS_NEGATIVE_NUMBER.getRespDesc());
        }
    }

    /**
     * 查询对客户营销活动单日统计表数据
     *
     * @param instId    法人机构号
     * @param mcNo      营销活动编号
     * @param ruleIndex 规则顺序号
     * @param txnDate   交易日期
     * @return cc.rengu.igas.momp.common.entity.TMStat2CDay 对客户营销活动单日统计表
     * @throws Exception 异常信息
     * @author JL Pang
     * @since 2020/11/10 9:52
     */
    private TMStat2CDay selectToClientMcDayStatistics(String instId, String mcNo, String ruleIndex, String txnDate) throws Exception {

        TMStat2CDay tmStat2CDay = new TMStat2CDay();
        tmStat2CDay.setInstId(instId);
        tmStat2CDay.setMcNo(mcNo);
        tmStat2CDay.setRuleIndex(ruleIndex);
        tmStat2CDay.setTxnDate(txnDate);

        TMStat2CDayMapper tmStat2CDayMapper = new TMStat2CDayMapperImpl();
        return tmStat2CDayMapper.selectToClientMcDayStatistics(tmStat2CDay);
    }

    /**
     * 校验用户参与优惠次数
     *
     * @return boolean
     * @author liujinan
     * @date 2020/11/11 16:36
     */
    public boolean checkIsUserReachLimit(Object mcInfoObject, List<TMMcUserInfo> tmMcUserInfoList) throws Exception {

        String mcNo, restriction, mcType, mcStartDate;
        //按活动类型获取数据
        if (mcInfoObject instanceof TMMcMoneyOffInfo) {
            mcNo = ((TMMcMoneyOffInfo) mcInfoObject).getMcNo();
            restriction = ((TMMcMoneyOffInfo) mcInfoObject).getRestriction();
            mcType = ((TMMcMoneyOffInfo) mcInfoObject).getMcType();
            mcStartDate = ((TMMcMoneyOffInfo) mcInfoObject).getMcStartDate();
        } else {
            mcNo = ((TMMcCouponInfo) mcInfoObject).getMcNo();
            restriction = ((TMMcCouponInfo) mcInfoObject).getRestriction();
            mcType = ((TMMcCouponInfo) mcInfoObject).getMcType();
            mcStartDate = ((TMMcCouponInfo) mcInfoObject).getMcStartDate();
        }

        //获取用户参与营销活动次数  当日的统计数据
        TMStat2CUserDayTransCount tmStat2CUserDayTransCount = getUserAttendMcCountDay(globalTxnDate, globalUserId, mcNo);
        int todayQtyAcc = tmStat2CUserDayTransCount.getDayPaymentCount();
        tmStat2CUserDayTransCount.setMcType(mcType);
        tmStat2CUserDayTransCount.setMcStartDate(mcStartDate);

        //当tmMcUserInfoList为null时活动为不指定用户
        if (null == tmMcUserInfoList) {
            rglog.info("机构<{}> 营销活动<{}> 用户范围为所有用户，开始判断用户参与次数限制....", globalInstId, mcNo);
            int totalQtyAcc = 0;
            String a[] = discountId.split(",");
            for (int i = 0; i < a.length; i++) {
                //获取用户参与营销活动次数  当日的统计数据
                TMStat2CUserDayTransCount newTmStat2CUserDayTransCount = getUserAttendMcCountDay(globalTxnDate, a[i], mcNo);
                newTmStat2CUserDayTransCount.setMcType(mcType);
                newTmStat2CUserDayTransCount.setMcStartDate(mcStartDate);
                int userQtyAcc = selectUserIdTotalQtyAcc(mcNo, newTmStat2CUserDayTransCount);
                if (userQtyAcc == CommonConstant.MINUS_ONE) {
                    rglog.info("获取编号<{}>用户统计表数据异常", a[i]);
                    return false;
                } else {
                    rglog.info("用户编号<{}>参与活动次数<{}>", a[i], userQtyAcc);
                    totalQtyAcc = totalQtyAcc + userQtyAcc;
                }

            }
            rglog.info("上送多个userId<{}>总共参与活动次数<{}>", discountId, totalQtyAcc);
            if (totalQtyAcc >= Integer.parseInt(restriction)) {
                rglog.info("userId<{}>总共参与活动次数<{}>大于等于活动优惠次数<{}>，不予优惠", discountId, totalQtyAcc, restriction);
                return false;
            } else {
                rglog.info("userId<{}>总共参与活动次数<{}>小于活动优惠次数<{}>，给予优惠", discountId, totalQtyAcc, restriction);
            }
        } else {
            rglog.info("机构<{}> 营销活动<{}> 用户范围为指定用户范围，开始判断用户参与次数限制....", globalInstId, mcNo);
            //营销活动用户信息 指定用户不能配置多个，配置多个可能存在问题
            TMMcUserInfo tmMcUserInfo = tmMcUserInfoList.get(CommonConstant.ZERO);
            //账户类型
            String acctType = tmMcUserInfo.getAcctType();

            //当账户类型为手机号或银行卡号时校验优惠次数
            if (CommonConstant.ZERO_COMMON_CONSTANT.equals(acctType) || CommonConstant.ONE_COMMON_CONSTANT.equals(acctType)) {
                boolean isReachUserLimit = isReachUserLimit(mcNo, tmStat2CUserDayTransCount, restriction);
                if (!isReachUserLimit) {
                    return false;
                }
            }

            //当账户类型为卡bin时校验优惠次数
            if (CommonConstant.TWO_COMMON_CONSTANT.equals(acctType)) {

                //每日优惠次数需要限制
                if (null != tmMcUserInfo.getDayRestriction() && !CommonConstant.ZERO_COMMON_CONSTANT.equals(tmMcUserInfo.getDayRestriction())) {
                    //判断用户参与活动次数是否超过活动配置的限制次数
                    if (todayQtyAcc >= Integer.parseInt(tmMcUserInfo.getDayRestriction())) {
                        rglog.error("用户<{}> 营销活动<{}> 用户当日已参加此活动次数<{}> 大于等于单日最大限制<{}>，不可再参与本活动！", globalUserId, mcNo, todayQtyAcc, tmMcUserInfo.getDayRestriction());
                        return false;
                    }
                }

                //每周优惠次数需要限制
                if (null != tmMcUserInfo.getWeekRestriction() && !CommonConstant.ZERO_COMMON_CONSTANT.equals(tmMcUserInfo.getWeekRestriction())) {
                    boolean isReachUserWeekLimit = isReachUserWeekLimit(tmMcUserInfo, tmStat2CUserDayTransCount, mcNo);
                    if (!isReachUserWeekLimit) {
                        return false;
                    }
                }

                //每月优惠次数需要限制
                if (null != tmMcUserInfo.getMonthRestriction() && !CommonConstant.ZERO_COMMON_CONSTANT.equals(tmMcUserInfo.getMonthRestriction())) {
                    boolean isReachUserMonthLimit = isReachUserMonthLimit(tmMcUserInfo, tmStat2CUserDayTransCount, mcNo);
                    if (!isReachUserMonthLimit) {
                        return false;
                    }
                }

                //每季度优惠次数需要限制
                if (null != tmMcUserInfo.getQuerterRestriction() && !CommonConstant.ZERO_COMMON_CONSTANT.equals(tmMcUserInfo.getQuerterRestriction())) {
                    boolean isReachUserQuarterLimit = isReachUserQuarterLimit(tmMcUserInfo, tmStat2CUserDayTransCount, mcNo);
                    if (!isReachUserQuarterLimit) {
                        return false;
                    }
                }

                //每年优惠次数需要限制
                if (null != tmMcUserInfo.getYearRestriction() && !CommonConstant.ZERO_COMMON_CONSTANT.equals(tmMcUserInfo.getYearRestriction())) {
                    boolean isReachUserYearLimit = isReachUserYearLimit(tmMcUserInfo, tmStat2CUserDayTransCount, mcNo);
                    if (!isReachUserYearLimit) {
                        return false;
                    }
                }

                //整个活动期间优惠次数需要限制
                if (null != tmMcUserInfo.getRestriction() && !CommonConstant.ZERO_COMMON_CONSTANT.equals(tmMcUserInfo.getRestriction())) {
                    boolean isReachUserLimit = isReachUserLimit(mcNo, tmStat2CUserDayTransCount, tmMcUserInfo.getRestriction());
                    if (!isReachUserLimit) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * 获取对客营销活动用户单日统计表数据
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/12 23:40
     */
    private TMStat2CUserDay getToClientMcUserDayStatistics(String mcNo, String txnDate) throws Exception {

        /* 查询对客户营销活动用户单日统计表*/
        TMStat2CUserDay tmStat2CUserDay = selectToClientMcUserDayStatisticsByPK(globalInstId, mcNo, globalUserId, txnDate);
        if (null == tmStat2CUserDay) {
            rglog.info("机构<{}> 营销活动<{}> 用户<{}> 日期<{}> 对客户营销活动用户单日统计表无数据!", globalInstId, mcNo, globalUserId, txnDate);

            tmStat2CUserDay = new TMStat2CUserDay();
            tmStat2CUserDay.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            tmStat2CUserDay.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            tmStat2CUserDay.setTxnAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);
        }

        return tmStat2CUserDay;
    }

    /**
     * 获取对客营销活动用户月统计表数据
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/12 23:40
     */
    private TMStat2CUserMonth getToClientMcUserMonthStatistics(String mcNo, String month, String mcType, String mcStartDate) throws Exception {

        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);
        String firstDayThisMonth = MompDateUtil.getCurrentMonthFirstDay();
        //当前月份
        String thisMonth = globalTxnDate.substring(0, 6);

        //批量任务执行最后日期
        String batchDate, batchMonth;
        //查询统计信息备份表批次信息 查询营销活动信息表的批量处理情况即可
        String statPrimaryKey = "UserStatPeriod" + globalInstId + "_" + mcNo;
        TMStatBak tmStatBak = selectTMStatBakByStatPrimaryKey(globalInstId, mcType, statPrimaryKey);
        //批次表为空，从来没执行过批量任务
        if (null == tmStatBak) {
            //从来没执行过批量任务，则从活动开始的第一天开始取数据
            batchDate = mcStartDate;
            batchMonth = "";
        } else {
            batchDate = DateUtil.getBaseDateOffsetDay(tmStatBak.getBatchDate(), 1);
            batchMonth = batchDate.substring(0, 6);
        }

        /* 查询对客户营销活动用户月统计表*/
        TMStat2CUserMonth tmStat2CUserMonth = selectToClientMcUserMonthStatisticsByPK(globalInstId, mcNo, globalUserId, month);
        if (null == tmStat2CUserMonth) {
            rglog.info("机构<{}> 营销活动<{}> 用户<{}> 月份<{}> 对客户营销活动用户月统计表无数据!", globalInstId, mcNo, globalUserId, month);
            //用户可能从来没有做过交易，也有可能是昨天做过，但是批量还没有处理完成
            tmStat2CUserMonth = new TMStat2CUserMonth();
            tmStat2CUserMonth.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            tmStat2CUserMonth.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            tmStat2CUserMonth.setTxnAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);

        }
        if (StringUtil.isNullorEmpty(batchMonth)) {
            //没有跑批记录 判断是不是活动开始的第一个月并且查询月是本月
            if (month.equals(mcStartDate.substring(0, 6)) && month.equals(thisMonth)) {
                //查询月是活动开始的月份 只需取单日明细表到活动开始日期
            } else {
                //查询月不是活动开始月 需取查询月1号到查询月最后一天的数据
                if (!month.equals(thisMonth)) {
                    lastDate = MompDateUtil.getMonthTheLastDay(month);
                }
                if (!month.equals(mcStartDate.substring(0, 6))) {
                    batchDate = month.concat("01");
                }
            }
        } else {//有跑批记录  判断最后跑批日期是不是在查询月内
            if (month.equals(batchMonth) && month.equals(thisMonth)) {
                //跑批日期在查询月内  需取昨天到最后跑批日期的单日明细
            } else {
                //判断查询月是否大于跑批最后月
                if (Integer.parseInt(batchMonth) < Integer.parseInt(month)) {
                    batchDate = month.concat("01");
                }
                if (!month.equals(thisMonth)) {
                    lastDate = MompDateUtil.getMonthTheLastDay(month);
                }
            }

        }

        //批量处理的日期小于昨天的日期，则需要取之前的数据
        while (DateUtil.compareDate(batchDate, lastDate) <= 0) {
            //循环获取单日统计表数据并累加
            TMStat2CUserDayTransCount TMStat2CUserDayTransCountDay = getUserAttendMcCountDay(batchDate, discountId, mcNo);
            if (null == TMStat2CUserDayTransCountDay) {
                rglog.error("查询用户<{}>活动<{}>对客活动单日统计表 数据查询失败!", discountId, mcNo);
                TMStat2CUserDayTransCountDay = new TMStat2CUserDayTransCount();
                TMStat2CUserDayTransCountDay.setDayPaymentCount(CommonConstant.ZERO);
                TMStat2CUserDayTransCountDay.setDayRefundCount(CommonConstant.ZERO);
            }
            copytmStat2CUserMonthData(tmStat2CUserMonth, TMStat2CUserDayTransCountDay);
            //将批次日期加一天继续判断
            batchDate = DateUtil.getBaseDateOffsetDay(batchDate, 1);
        }
        return tmStat2CUserMonth;
    }

    /**
     * 获取对客营销活动用户统计表数据
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/12 23:40
     */
    private TMStat2CUser getToClientMcUserStatistics(String mcNo, String userId, String mcType, String mcStartDate) throws Exception {

        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);

        /* 查询对客户营销活动用户统计表*/
        TMStat2CUser tmStat2CUser = selectToClientMcUserStatisticsByPK(globalInstId, mcNo, userId);
        if (null == tmStat2CUser) {
            rglog.info("机构<{}> 营销活动<{}> 用户<{}> 对客户营销活动用户统计表无数据!", globalInstId, mcNo, userId);
            //用户可能从来没有做过交易，也有可能是昨天做过，但是批量还没有处理完成
            tmStat2CUser = new TMStat2CUser();
            tmStat2CUser.setTotalQtyAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            tmStat2CUser.setTotalAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);
            tmStat2CUser.setTxnAmtAcc(CommonConstant.ZERO_COMMON_CONSTANT);

            //此种情况需要取前一天的数据（即使没做过交易，则前一天数据为0也不会有影响）
            batchStatusStat = CommonConstant.FLAG_SET;

        }
        String batchDate;
        //查询统计信息备份表批次信息 查询营销活动信息表的批量处理情况即可
        String statPrimaryKey = "UserStat" + globalInstId + "_" + mcNo;
        TMStatBak tmStatBak = selectTMStatBakByStatPrimaryKey(globalInstId, mcType, statPrimaryKey);
        //批次表为空，从来没执行过批量任务
        if (null == tmStatBak) {
            //从来没执行过批量任务，则从活动开始的第一天开始取数据
            batchDate = mcStartDate;
        } else {
            batchDate = DateUtil.getBaseDateOffsetDay(tmStatBak.getBatchDate(), 1);
        }
        //批量处理的日期小于昨天的日期，则需要取之前的数据
        while (DateUtil.compareDate(batchDate, lastDate) <= 0) {
            //获取的数据累加到活动统计中
            TMStat2CUserDayTransCount TMStat2CUserDayTransCountDay = getUserAttendMcCountDay(batchDate, userId, mcNo);
            if (null == TMStat2CUserDayTransCountDay) {
                rglog.error("查询用户<{}>活动<{}>对客活动单日统计表 数据查询失败!", userId, mcNo);
                TMStat2CUserDayTransCountDay = new TMStat2CUserDayTransCount();
                TMStat2CUserDayTransCountDay.setDayPaymentCount(CommonConstant.ZERO);
                TMStat2CUserDayTransCountDay.setDayRefundCount(CommonConstant.ZERO);
            }
            copytmStat2CUserData(tmStat2CUser, TMStat2CUserDayTransCountDay);
            //将批次日期加一天继续判断
            batchDate = DateUtil.getBaseDateOffsetDay(batchDate, 1);
        }

        return tmStat2CUser;
    }

    /**
     * 查询用户某天已参与某个营销活动统计
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/12 10:10
     */
    private TMStat2CUserDayTransCount getUserAttendMcCountDay(String txnDate, String userId, String mcNo) throws Exception {
        rglog.info("机构<{}> 用户<{}> 营销活动编号<{}> 日期<{}> 开始获取用户已参加此活动次数", globalInstId, userId, mcNo, txnDate);

        String transStatus, bizStatus, txnNum, origTxnDate;
        int dayPaymentCount = 0, dayRefundCount = 0, weekRefundCount = 0, querterRefundCount = 0, monthRefundCount = 0, yearRefundCount = 0;

        TMTxnOrderMapper tmTxnOrderMapper = new TMTxnOrderMapperImpl();
        TMTxnOrderDetMapper tmTxnOrderDetMapper = new TMTxnOrderDetMapperImpl();

        List<TMTxnOrderDet> userOrderDetialList = tmTxnOrderDetMapper.selectUserOrderDetailListInfo(globalInstId, txnDate, userId, mcNo);
        if (null == userOrderDetialList) {
            rglog.info("未获取到用户<{}> 营销活动<{}> 日期<{}> 的交易明细信息！", userId, mcNo, txnDate);
        } else {
            rglog.info("获取到用户<{}> 营销活动<{}> 日期<{}> 的交易明细信息,开始查询交易流水信息...", userId, mcNo, txnDate);

            for (TMTxnOrderDet tmTxnOrderDet : userOrderDetialList) {
                TMTxnOrder tmTxnOrder = tmTxnOrderMapper.selectTransactionOrderInfo(globalInstId, txnDate, tmTxnOrderDet.getFrontSeqNum());
                if (null == tmTxnOrder) {
                    rglog.error("未取到法人机构<{}> 日期<{}> 流水号<{}>的原始交易信息!", globalInstId, txnDate, tmTxnOrderDet.getFrontSeqNum());
                    throw new BizException(RespCodeEnum.TXN_REGULATION_FAILED_ERROR.getRespCode(), RespCodeEnum.TXN_REGULATION_FAILED_ERROR.getRespDesc());
                }

                transStatus = tmTxnOrder.getTransStatus();
                bizStatus = tmTxnOrder.getBizStatus();
                txnNum = tmTxnOrder.getTxnNum();
                //如果交易是支付成功的
                if (TransStatusEnum.TRANS_SUCC.getStatus().equals(transStatus) && "P01MO003".equals(txnNum)) {
                    if (BizStatusEnum.PROCESS_SUCCESS.getBizStatusCode().equals(bizStatus) && txnDate.equals(globalTxnDate)) {
                        rglog.info("获取到流水<{}> 为合并支付交易，且交易状态为成功!", tmTxnOrderDet.getFrontSeqNum());
                        dayPaymentCount++;
                    } else if (!txnDate.equals(globalTxnDate) && (BizStatusEnum.PROCESS_SUCCESS.getBizStatusCode().equals(bizStatus)
                            || BizStatusEnum.PROCESS_REFUNDED.getBizStatusCode().equals(bizStatus)
                            || BizStatusEnum.PROCESS_PARTIALLY_REFUNDED.getBizStatusCode().equals(bizStatus)
                            || BizStatusEnum.PROCESS_REGULATED.getBizStatusCode().equals(bizStatus))) {
                        //这样统计是因为昨天的批量任务没跑完 需要加上昨天交易今天退货的原正向交易笔数，因合并冲正没有流水，所以不需要加上原交易已经冲正的流水
                        rglog.info("获取到交易流水<{}>交易日期<{}>不是今天<{}>的合并支付交易,此交易为昨天交易今天退货或昨天交易昨天退货或昨天交易未退货的交易", tmTxnOrderDet.getFrontSeqNum(), txnDate, globalTxnDate);
                        dayPaymentCount++;
                    } else {
                    }
                }
                //如果交易是退款成功的，或者冲正成功的,或调账成功
                if (TransStatusEnum.TRANS_SUCC.getStatus().equals(transStatus) &&
                        BizStatusEnum.PROCESS_SUCCESS.getBizStatusCode().equals(bizStatus) &&
                        ("P04MO002".equals(txnNum) || "P02MO001".equals(txnNum) || "P08MO001".equals(txnNum))) {
                    origTxnDate = tmTxnOrder.getOrigTxnDate();
                    //原正向交易日期和退款/冲正日期是同一天，则此笔退款/冲正不纳入今天的统计,原正向交易日期不和退款/冲正同一天，则纳入当日的退款/冲正统计
                    if (!txnDate.equals(origTxnDate)) {
                        dayRefundCount++;
                        rglog.info("流水<{}> 交易为 <{}>，交易状态为成功,原交易日期<{}> 与退货日期<{}>不是同一天!", tmTxnOrderDet.getFrontSeqNum(), txnNum, origTxnDate, txnDate);
                    }

                    //获取的统计不是今天（一般是昨天的），此时由于上边流程中把退货的所有交易归为支付成功，由于我们不统计当天交易当天退货的笔数，所以在这里减去
                    if (!txnDate.equals(globalTxnDate) && txnDate.equals(origTxnDate)) {
                        dayPaymentCount--;
                        rglog.info("流水<{}> 交易为 <{}>，统计交易日期<{}>，当天交易当天发生退货，不统计到当天成功支付笔数!", tmTxnOrderDet.getFrontSeqNum(), txnNum, txnDate, origTxnDate);
                    }
                    //原正向交易的所在周和退款/冲正交易是否是在同一个周
                    LocalDate inputDate = LocalDate.parse(txnDate, DateTimeFormatter.BASIC_ISO_DATE);
                    LocalDate beginDayOfWeek = inputDate.with(DayOfWeek.MONDAY);

                    LocalDate origInputDate = LocalDate.parse(origTxnDate, DateTimeFormatter.BASIC_ISO_DATE);
                    LocalDate origBeginDayOfWeek = origInputDate.with(DayOfWeek.MONDAY);
                    if (beginDayOfWeek.isEqual(origBeginDayOfWeek) && !txnDate.equals(origTxnDate)) {
                        weekRefundCount++;
                        rglog.info("流水<{}> 交易为 <{}>，交易状态为成功,原交易日期<{}> 与退货日期在同一周!", tmTxnOrderDet.getFrontSeqNum(), txnNum, origTxnDate);
                    }

                    //原正向交易的月份和退款/冲正月份是同一个，则此笔退款/冲正不纳入当月的统计,原正向交易月份不和退款/冲正同一个，则纳入当月的退款/冲正统计
                    String txnMonth = txnDate.substring(0, 6);
                    String origTxnMonth = origTxnDate.substring(0, 6);
                    if (txnMonth.equals(origTxnMonth) && !txnDate.equals(origTxnDate)) {
                        monthRefundCount++;
                        rglog.info("流水<{}> 交易为 <{}>，交易状态为成功,原交易日期<{}> 与退货日期在同一月!", tmTxnOrderDet.getFrontSeqNum(), txnNum, origTxnDate);
                    }

                    //原正向交易的所在季度和退款/冲正交易是否是在同一个季度
                    Month month = inputDate.getMonth();
                    Month firstMonthOfQuarter = month.firstMonthOfQuarter();

                    Month origMonth = origInputDate.getMonth();
                    Month origFirstMonthOfQuarter = origMonth.firstMonthOfQuarter();

                    LocalDate quarterFirstDay = LocalDate.of(inputDate.getYear(), firstMonthOfQuarter, 1);
                    LocalDate oriQuarterFirstDay = LocalDate.of(origInputDate.getYear(), origFirstMonthOfQuarter, 1);

                    if (quarterFirstDay.isEqual(oriQuarterFirstDay) && !txnDate.equals(origTxnDate)) {
                        querterRefundCount++;
                        rglog.info("流水<{}> 交易为 <{}>，交易状态为成功,原交易日期<{}> 与退货日期在同一季度!", tmTxnOrderDet.getFrontSeqNum(), txnNum, origTxnDate);
                    }

                    //原正向交易的年份和退款/冲正年份是同一个，则此笔退款/冲正不纳入当月的统计,原正向交易年份不和退款/冲正同一个，则纳入当月的退款/冲正统计
                    String txnYear = txnDate.substring(0, 4);
                    String origTxnYear = origTxnDate.substring(0, 4);
                    if (txnYear.equals(origTxnYear) && !txnDate.equals(origTxnDate)) {
                        yearRefundCount++;
                        rglog.info("流水<{}> 交易为 <{}>，交易状态为成功,原交易日期<{}> 与退货日期在同一年!", tmTxnOrderDet.getFrontSeqNum(), txnNum, origTxnDate);
                    }
                }
            }
        }

        TMStat2CUserDayTransCount tmStat2CUserDayTransCount = new TMStat2CUserDayTransCount();
        tmStat2CUserDayTransCount.setInstId(globalInstId);
        tmStat2CUserDayTransCount.setMcNo(mcNo);
        tmStat2CUserDayTransCount.setTransDate(txnDate);
        tmStat2CUserDayTransCount.setUserId(userId);
        tmStat2CUserDayTransCount.setDayPaymentCount(dayPaymentCount);
        tmStat2CUserDayTransCount.setDayRefundCount(dayRefundCount);
        tmStat2CUserDayTransCount.setWeekRefundCount(weekRefundCount);
        tmStat2CUserDayTransCount.setMonthRefundCount(monthRefundCount);
        tmStat2CUserDayTransCount.setQuerterRefundCount(querterRefundCount);
        tmStat2CUserDayTransCount.setYearRefundCount(yearRefundCount);

        return tmStat2CUserDayTransCount;
    }

    /**
     * 用户参与活动 周维度是否超限
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/13 23:40
     */
    private boolean isReachUserWeekLimit(TMMcUserInfo tmMcUserInfo, TMStat2CUserDayTransCount tmStat2CUserDayTransCount, String mcNo) throws Exception {
        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);
        int todayQtyAcc = tmStat2CUserDayTransCount.getDayPaymentCount();

        //累计优惠笔数
        int totalQtyAccWeek = 0;

        LocalDate inputDate = LocalDate.parse(globalTxnDate, DateTimeFormatter.BASIC_ISO_DATE);
        LocalDate beginDayOfWeek = inputDate.with(DayOfWeek.MONDAY);
        String firstDayOfWeek = beginDayOfWeek.toString().replaceAll("-", "");

        //今天是周的第一天，则总优惠笔数即为今天发生的优惠笔数
        if (globalTxnDate.equals(firstDayOfWeek))
            totalQtyAccWeek = todayQtyAcc;
        else {
            int i = 0;
            boolean isGetBeforeSecondData = false;
            TMStat2CUserDay tmStat2CUserDay;

            String date = firstDayOfWeek;
            //今天不是周的第一天，则取前一天的数据，判断前一天是否有数据，如果没有则需要取昨天的前一天的数据
            while (i < 6) {
                i++;
                if (globalTxnDate.equals(date)) {
                    //如果获取日期已经是今天了，则退出
                    break;
                }

                //当日的统计数据
                tmStat2CUserDay = getToClientMcUserDayStatistics(mcNo, date);
                totalQtyAccWeek = totalQtyAccWeek + Integer.parseInt(tmStat2CUserDay.getTotalQtyAcc());

                //判断当前获取的日统计数据为昨日的
                if (lastDate.equals(date)) {
                    //当获取到的昨日单日统计数据为0时，则需要自己获取昨天的数据
                    if (CommonConstant.ZERO_COMMON_CONSTANT.equals(tmStat2CUserDay.getTotalQtyAcc())) {
                        isGetBeforeSecondData = true;
                    }
                }

                date = DateUtil.getBaseDateOffsetDay(date, 1);
            }
            if (isGetBeforeSecondData) {
                //获取昨日统计数据
                //获取的数据累加到活动统计中
                TMStat2CUserDayTransCount tmStat2CUserDayTransCountLastDay = getUserAttendMcCountDay(lastDate, discountId, mcNo);

                totalQtyAccWeek = totalQtyAccWeek + tmStat2CUserDayTransCountLastDay.getDayPaymentCount() - tmStat2CUserDayTransCountLastDay.getWeekRefundCount();
            }
            //加上当日的统计值
            totalQtyAccWeek = totalQtyAccWeek + todayQtyAcc - tmStat2CUserDayTransCount.getWeekRefundCount();
        }

        //判断用户参与活动次数是否超过活动配置的限制次数
        if (totalQtyAccWeek >= Integer.parseInt(tmMcUserInfo.getWeekRestriction())) {
            rglog.error("用户<{}> 营销活动<{}> 用户当前周已参加此活动次数<{}> 大于等于单周最大限制<{}>，不可再参与本活动！", globalUserId, mcNo, totalQtyAccWeek, tmMcUserInfo.getWeekRestriction());
            return false;
        }

        return true;
    }

    /**
     * 用户参与活动 月维度是否超限
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/13 23:40
     */
    private boolean isReachUserMonthLimit(TMMcUserInfo tmMcUserInfo, TMStat2CUserDayTransCount tmStat2CUserDayTransCount, String mcNo) throws Exception {

        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);
        String month = globalTxnDate.substring(0, 6);
        int todayQtyAcc = tmStat2CUserDayTransCount.getDayPaymentCount();
        String mcType = tmStat2CUserDayTransCount.getMcType();
        String mcStartDate = tmStat2CUserDayTransCount.getMcStartDate();

        TMStat2CUserMonth tmStat2CUserMonth = getToClientMcUserMonthStatistics(mcNo, month, mcType, mcStartDate);

        if (null == tmStat2CUserMonth) {
            rglog.error("机构<{}> 对客营销活动<{}> 用户<{}> 获取营销活动用户月份<{}> 统计表数据异常，不可参与本活动!", globalInstId, mcNo, globalUserId, month);
            return false;
        }

        //累计优惠笔数
        int totalQtyAcc = Integer.parseInt(tmStat2CUserMonth.getTotalQtyAcc());

        //活动统计的加当日统计的
        totalQtyAcc = totalQtyAcc + todayQtyAcc - tmStat2CUserDayTransCount.getMonthRefundCount();

        rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数<{}>,活动配置的每个用户每月最多参与次数<{}>", globalUserId, mcNo, totalQtyAcc, tmMcUserInfo.getMonthRestriction());
        //判断用户参与活动次数是否超过活动配置的限制次数
        if (totalQtyAcc >= Integer.parseInt(tmMcUserInfo.getMonthRestriction())) {
            rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数大于等于每月最大限制，不可再参与本活动！", globalUserId, mcNo);
            return false;
        }

        return true;
    }

    /**
     * 用户参与活动 季度维度是否超限
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/13 23:40
     */
    private boolean isReachUserQuarterLimit(TMMcUserInfo tmMcUserInfo, TMStat2CUserDayTransCount tmStat2CUserDayTransCount, String mcNo) throws Exception {

        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);
        int todayQtyAcc = tmStat2CUserDayTransCount.getDayPaymentCount();

        //当前月份
        String nowMonth = globalTxnDate.substring(0, 6);
        //累计优惠笔数
        int totalQtyAccQuarter = 0;

        //获取当前日期季度的第一天
        LocalDate inputDate = LocalDate.parse(globalTxnDate, DateTimeFormatter.BASIC_ISO_DATE);
        Month month = inputDate.getMonth();
        Month firstMonthOfQuarter = month.firstMonthOfQuarter();
        LocalDate quarterFirstDay = LocalDate.of(inputDate.getYear(), firstMonthOfQuarter, 1);
        String firstDayOfQuarter = quarterFirstDay.toString().replaceAll("-", "");

        String quarterFirstMonth = firstDayOfQuarter.substring(0, 6);
        String mcType = tmStat2CUserDayTransCount.getMcType();
        String mcStartDate = tmStat2CUserDayTransCount.getMcStartDate();
        //活动开始月
        String mcMonth = mcStartDate.substring(0, 6);

        //获取月统计表数据
        //今天是季度的第一个月，则季度值为月统计表中本月的统计值
        if (nowMonth.equals(quarterFirstMonth)) {
            TMStat2CUserMonth tmStat2CUserMonth = getToClientMcUserMonthStatistics(mcNo, nowMonth, mcType, mcStartDate);

            if (null == tmStat2CUserMonth) {
                rglog.error("机构<{}> 对客营销活动<{}> 用户<{}> 获取营销活动用户月份<{}> 统计表数据异常，不可参与本活动!", globalInstId, mcNo, globalUserId, nowMonth);
                return false;
            }

            //累计优惠笔数
            totalQtyAccQuarter = Integer.parseInt(tmStat2CUserMonth.getTotalQtyAcc());

        } else {
            int i = 0;
            String everyMonth = quarterFirstMonth;
            //取当前季度每个月的统计值
            while (i < 3) {
                i++;
                if (new BigDecimal(mcMonth).compareTo(new BigDecimal(everyMonth)) > 0) {
                    everyMonth = MompDateUtil.getBaseDateOffsetMonth(everyMonth, 1);
                    continue;
                }
                TMStat2CUserMonth tmStat2CUserMonth = getToClientMcUserMonthStatistics(mcNo, everyMonth, mcType, mcStartDate);

                if (null == tmStat2CUserMonth) {
                    rglog.error("机构<{}> 对客营销活动<{}> 用户<{}> 获取营销活动用户月份<{}> 统计表数据异常，不可参与本活动!", globalInstId, mcNo, globalUserId, everyMonth);
                    return false;
                }

                //累计优惠笔数
                totalQtyAccQuarter = totalQtyAccQuarter + Integer.parseInt(tmStat2CUserMonth.getTotalQtyAcc());
                //如果当前获取的月份统计值即为当前日期所在的月，则循环结束
                if (nowMonth.equals(everyMonth)) {
                    break;
                }

                everyMonth = MompDateUtil.getBaseDateOffsetMonth(everyMonth, 1);
            }
        }

        //活动统计的加当日统计的
        totalQtyAccQuarter = totalQtyAccQuarter + todayQtyAcc - tmStat2CUserDayTransCount.getQuerterRefundCount();

        //判断用户参与活动次数是否超过活动配置的限制次数
        if (totalQtyAccQuarter >= Integer.parseInt(tmMcUserInfo.getQuerterRestriction())) {
            rglog.error("用户<{}> 营销活动<{}> 用户当前季度已参加此活动次数<{}> 大于等于单季度最大限制<{}>，不可再参与本活动！", globalUserId, mcNo, totalQtyAccQuarter, tmMcUserInfo.getQuerterRestriction());
            return false;
        }

        return true;
    }

    /**
     * 用户参与活动 年维度是否超限
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/13 23:40
     */
    private boolean isReachUserYearLimit(TMMcUserInfo tmMcUserInfo, TMStat2CUserDayTransCount tmStat2CUserDayTransCount, String mcNo) throws Exception {

        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);
        int todayQtyAcc = tmStat2CUserDayTransCount.getDayPaymentCount();
        //当前月份
        String nowMonth = globalTxnDate.substring(0, 6);
        //累计优惠笔数
        int totalQtyAccYear = 0;

        //获取当前日期季度的第一天
        LocalDate inputDate = LocalDate.parse(globalTxnDate, DateTimeFormatter.BASIC_ISO_DATE);
        LocalDate quarterFirstDay = LocalDate.of(inputDate.getYear(), Month.JANUARY, 1);
        String firstDayOfQuarter = quarterFirstDay.toString().replaceAll("-", "");

        String yearFirstMonth = firstDayOfQuarter.substring(0, 6);
        String mcType = tmStat2CUserDayTransCount.getMcType();
        String mcStartDate = tmStat2CUserDayTransCount.getMcStartDate();
        //活动开始月
        String mcMonth = mcStartDate.substring(0, 6);

        //获取月统计表数据
        //今天在今年的第一个月，则年统计值为月统计表中本月的统计值
        if (nowMonth.equals(yearFirstMonth)) {
            TMStat2CUserMonth tmStat2CUserMonth = getToClientMcUserMonthStatistics(mcNo, nowMonth, mcType, mcStartDate);

            if (null == tmStat2CUserMonth) {
                rglog.error("机构<{}> 对客营销活动<{}> 用户<{}> 获取营销活动用户月份<{}> 统计表数据异常，不可参与本活动!", globalInstId, mcNo, globalUserId, nowMonth);
                return false;
            }

            //累计优惠笔数
            totalQtyAccYear = Integer.parseInt(tmStat2CUserMonth.getTotalQtyAcc());

        } else {
            int i = 0;
            String everyMonth = yearFirstMonth;
            //取当年每个月的统计值
            while (i < 12) {
                i++;
                if (new BigDecimal(mcMonth).compareTo(new BigDecimal(everyMonth)) > 0) {
                    everyMonth = MompDateUtil.getBaseDateOffsetMonth(everyMonth, 1);
                    continue;
                }
                TMStat2CUserMonth tmStat2CUserMonth = getToClientMcUserMonthStatistics(mcNo, everyMonth, mcType, mcStartDate);

                if (null == tmStat2CUserMonth) {
                    rglog.error("机构<{}> 对客营销活动<{}> 用户<{}> 获取营销活动用户月份<{}> 统计表数据异常，不可参与本活动!", globalInstId, mcNo, globalUserId, everyMonth);
                    return false;
                }

                //累计优惠笔数
                totalQtyAccYear = totalQtyAccYear + Integer.parseInt(tmStat2CUserMonth.getTotalQtyAcc());
                //如果当前获取的月份统计值即为当前日期所在的月，则循环结束
                if (nowMonth.equals(everyMonth)) {
                    break;
                }

                everyMonth = MompDateUtil.getBaseDateOffsetMonth(everyMonth, 1);
            }
        }


        //活动统计的加当日统计的
        totalQtyAccYear = totalQtyAccYear + todayQtyAcc - tmStat2CUserDayTransCount.getYearRefundCount();

        //判断用户参与活动次数是否超过活动配置的限制次数
        if (totalQtyAccYear >= Integer.parseInt(tmMcUserInfo.getYearRestriction())) {
            rglog.error("用户<{}> 营销活动<{}> 用户当年已参加此活动次数<{}> 大于等于每年最大限制<{}>，不可再参与本活动！", globalUserId, mcNo, totalQtyAccYear, tmMcUserInfo.getYearRestriction());
            return false;
        }

        return true;
    }

    /**
     * 用户参与活动 整个活动期间是否超限
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/13 23:40
     */
    private boolean isReachUserLimit(String mcNo, TMStat2CUserDayTransCount tmStat2CUserDayTransCount, String restriction) throws Exception {

        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);
        int todayQtyAcc = tmStat2CUserDayTransCount.getDayPaymentCount();
        String mcType = tmStat2CUserDayTransCount.getMcType();
        String mcStartDate = tmStat2CUserDayTransCount.getMcStartDate();
        rglog.info("用户<{}> 营销活动<{}>该用户当日已参加此活动次数<{}>", globalUserId, mcNo, todayQtyAcc);

        //获取对客营销活动用户统计表数据
        TMStat2CUser tmStat2CUser = getToClientMcUserStatistics(mcNo, globalUserId, mcType, mcStartDate);

        if (null == tmStat2CUser) {
            rglog.error("机构<{}> 对客营销活动<{}> 用户<{}> 获取对客营销活动用户统计表数据异常，不可参与本活动!", globalInstId, mcNo, globalUserId);
            return false;
        }

        //累计优惠笔数
        int totalQtyAcc = Integer.parseInt(tmStat2CUser.getTotalQtyAcc());

        //活动统计的加当日统计的
        totalQtyAcc = totalQtyAcc + todayQtyAcc - tmStat2CUserDayTransCount.getDayRefundCount();

        rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数<{}>,活动配置的每个用户限制最多参与次数<{}>", globalUserId, mcNo, totalQtyAcc, restriction);
        //判断用户参与活动次数是否超过活动配置的限制次数
        if (totalQtyAcc >= Integer.parseInt(restriction)) {
            rglog.info("用户<{}> 营销活动<{}>该用户已参加此活动次数大于等于最大限制，不可再参与本活动！", globalUserId, mcNo);
            return false;
        }

        return true;
    }

    /**
     * 使用主键获取对客营销活动用户统计表单条数据
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/11 23:40
     */
    private TMStat2CUser selectToClientMcUserStatisticsByPK(String instId, String mcNo, String memberId) throws Exception {

        TMStat2CUserMapper tmStat2CUserMapper = new TMStat2CUserMapperImpl();

        TMStat2CUser tmStat2CUser = new TMStat2CUser();
        tmStat2CUser.setInstId(instId);
        tmStat2CUser.setMcNo(mcNo);
        tmStat2CUser.setMemberId(memberId);

        return tmStat2CUserMapper.selectToClientMcUserStatistics(tmStat2CUser);
    }

    /**
     * 使用主键获取对客营销活动用户月统计表单条数据
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/12 23:40
     */
    private TMStat2CUserMonth selectToClientMcUserMonthStatisticsByPK(String instId, String mcNo, String memberId, String month) throws Exception {

        TMStat2CUserMonthMapper tmStat2CUserMonthMapper = new TMStat2CUserMonthMapperImpl();

        TMStat2CUserMonth tmStat2CUserMonth = new TMStat2CUserMonth();
        tmStat2CUserMonth.setInstId(instId);
        tmStat2CUserMonth.setMcNo(mcNo);
        tmStat2CUserMonth.setMemberId(memberId);
        tmStat2CUserMonth.setMonth(month);

        return tmStat2CUserMonthMapper.selectToClientMcUserMonthStatistics(tmStat2CUserMonth);
    }

    /**
     * 使用主键获取对客营销活动用户单日统计表单条数据
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/12 23:40
     */
    private TMStat2CUserDay selectToClientMcUserDayStatisticsByPK(String instId, String mcNo, String memberId, String txnDate) throws Exception {

        TMStat2CUserDayMapper tmStat2CUserDayMapper = new TMStat2CUserDayMapperImpl();

        TMStat2CUserDay tmStat2CUserDay = new TMStat2CUserDay();
        tmStat2CUserDay.setInstId(instId);
        tmStat2CUserDay.setMcNo(mcNo);
        tmStat2CUserDay.setMemberId(memberId);
        tmStat2CUserDay.setTxnDate(txnDate);

        return tmStat2CUserDayMapper.selectToClientMcUserDayStatistics(tmStat2CUserDay);
    }

    /**
     * 卡券类转换内部对象
     *
     * @param tmMcCouponInfo  卡券类营销活动信息表
     * @param mcCouponTxnData (合并)支付使用卡券类交易信息
     * @author JL Pang
     * @since 2020/11/15 16:44
     */
    private void convertCouponMcInfo(TMMcCouponInfo tmMcCouponInfo, McCouponTxnData mcCouponTxnData) {

        /* 营销活动编号 */
        mcCouponTxnData.setMcNo(tmMcCouponInfo.getMcNo());
        /* 营销活动名称 */
        mcCouponTxnData.setMcName(tmMcCouponInfo.getMcName());
        /* 营销活动类型 */
        mcCouponTxnData.setMcType(tmMcCouponInfo.getMcType());
        /* 营销活动状态 */
        mcCouponTxnData.setMcStatus(tmMcCouponInfo.getMcStatus());
        /* 活动起始日期 */
        mcCouponTxnData.setMcStartDate(tmMcCouponInfo.getMcStartDate());
        /* 活动截止日期 */
        mcCouponTxnData.setMcEndDate(tmMcCouponInfo.getMcEndDate());
        /* 活动结束日期 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getMcActualEndDate())) {
            mcCouponTxnData.setMcActualEndDate(tmMcCouponInfo.getMcActualEndDate());
        }
        /* 活动时间标志 */
        mcCouponTxnData.setMcTimeFlag(tmMcCouponInfo.getMcTimeFlag());
        /* 出资方 */
        mcCouponTxnData.setSponsor(tmMcCouponInfo.getSponsor());
        /* 参与次数限制 */
        mcCouponTxnData.setRestriction(tmMcCouponInfo.getRestriction());
        /* 客户范围 */
        mcCouponTxnData.setClientRange(tmMcCouponInfo.getClientRange());
        /* 商户范围 */
        mcCouponTxnData.setMerchantRange(tmMcCouponInfo.getMerchantRange());
        /* 新增商户活动标志 */
        mcCouponTxnData.setNewMchntFlag(tmMcCouponInfo.getNewMchntFlag());
        /* 限制金额下限 */
        mcCouponTxnData.setAmtLimitFloor(tmMcCouponInfo.getAmtLimitFloor());
        /* 限制金额上限 */
        mcCouponTxnData.setAmtLimitCelling(tmMcCouponInfo.getAmtLimitCelling());
        /* 预算充值方式 */
        mcCouponTxnData.setBudgetRechargeMethod(tmMcCouponInfo.getBudgetRechargeMethod());
        /* 预算 */
        mcCouponTxnData.setBudget(tmMcCouponInfo.getBudget());
        /* 银行出资预算 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getBankBudget())) {
            mcCouponTxnData.setBankBudget(tmMcCouponInfo.getBankBudget());
        }
        /* 预期参与商户数量 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getExpectMchntQty())) {
            mcCouponTxnData.setExpectMchntQty(tmMcCouponInfo.getExpectMchntQty());
        }
        /* 银行出资比例 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getBankBudgetRatio())) {
            mcCouponTxnData.setBankBudgetRatio(tmMcCouponInfo.getBankBudgetRatio());
        }
        /* 购买标志 */
        mcCouponTxnData.setPurchaseFlag(tmMcCouponInfo.getPurchaseFlag());
        /* 卡券生效时间 */
        mcCouponTxnData.setAvailableDate(tmMcCouponInfo.getAvailableDate());
        /* 卡券有效期标志 */
        mcCouponTxnData.setCouponDateFlag(tmMcCouponInfo.getCouponDateFlag());
        /* 卡券有效起始日期 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getCouponStartDate())) {
            mcCouponTxnData.setCouponStartDate(tmMcCouponInfo.getCouponStartDate());
        }
        /* 卡券有效结束日期 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getCouponStartDate())) {
            mcCouponTxnData.setCouponEndDate(tmMcCouponInfo.getCouponEndDate());
        }
        /* 卡券相对周期 */
        mcCouponTxnData.setCouponPeriod(tmMcCouponInfo.getCouponPeriod());
        /* 卡券库存 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getCouponStartDate())) {
            mcCouponTxnData.setCouponInventory(tmMcCouponInfo.getCouponInventory());
        }
        /* 卡券已领取张数 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getCouponStartDate())) {
            mcCouponTxnData.setCouponClaimed(tmMcCouponInfo.getCouponClaimed());
        }
        /* 卡券未领取张数 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getCouponStartDate())) {
            mcCouponTxnData.setCouponRest(tmMcCouponInfo.getCouponRest());
        }
        /* 卡券已核销张数 */
        if (!StringUtil.isNullorEmpty(tmMcCouponInfo.getCouponStartDate())) {
            mcCouponTxnData.setCouponRedeemed(tmMcCouponInfo.getCouponRedeemed());
        }
        /* 审批状态 */
        mcCouponTxnData.setAuditStatus(tmMcCouponInfo.getAuditStatus());
    }

    /**
     * 卡券类规则信息赋值
     *
     * @param tmMcCouponRuleInfo 卡券类营销活动规则表
     * @param mcCouponTxnData    卡券类营销活动金额数据
     * @author JL Pang
     * @since 2020/11/16 10:52
     */
    private void copyCoupnRuleInfoAmountData(TMMcCouponRuleInfo tmMcCouponRuleInfo, McCouponTxnData mcCouponTxnData) {

        /* 法人机构号 */
        mcCouponTxnData.setInstId(tmMcCouponRuleInfo.getInstId());
        /* 营销活动编号 */
        mcCouponTxnData.setMcNo(tmMcCouponRuleInfo.getMcNo());
        /* 规则信息-顺序号 */
        mcCouponTxnData.setRuleIndex(tmMcCouponRuleInfo.getRuleIndex());
        /* 规则信息-活动门槛 */
        mcCouponTxnData.setCriteria(tmMcCouponRuleInfo.getCriteria());
        /* 单日可核销数量 */
        mcCouponTxnData.setDayRedeemLimit(tmMcCouponRuleInfo.getDayRedeemLimit());
        /* 卡券金额 */
        mcCouponTxnData.setCouponAmt(tmMcCouponRuleInfo.getDenomination());
        /* 卡券数量*/
        mcCouponTxnData.setQuantity(tmMcCouponRuleInfo.getQuantity());
    }

    /**
     * 卡券类营销活动交易限额处理
     *
     * @param mcCouponTxnData (合并)支付使用卡券类交易信息
     * @return int 返回码
     * @author JL Pang
     * @since 2020/11/16 10:52
     */
    private int checkCouponLimits(McCouponTxnData mcCouponTxnData) {
        //总预算
        String budget = mcCouponTxnData.getBudget();
        /* 规则信息-顺序号 */
        String ruleIndex = mcCouponTxnData.getRuleIndex();
        /* 规则信息-卡券数量 */
        BigDecimal quantity = new BigDecimal(mcCouponTxnData.getQuantity()).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);
        /* 规则信息-单日核销数量 */
        BigDecimal dayRedeemLimit = new BigDecimal(mcCouponTxnData.getDayRedeemLimit()).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);
        /* 当前累计历史优惠笔数-优惠前 */
        BigDecimal mcTotalQtyAcc = new BigDecimal(mcCouponTxnData.getMcTotalQtyAcc()).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);
        /* 当前当日累计优惠笔数-优惠前 */
        BigDecimal dayTotalQtyAcc = new BigDecimal(mcCouponTxnData.getDayTotalQtyAcc()).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);
        /* 总累计优惠笔数-优惠前 */
        BigDecimal totalQtyAcc = mcTotalQtyAcc.add(dayTotalQtyAcc).setScale(CommonConstant.DECIMAL_SCALE_ZERO, RoundingMode.HALF_UP);

        /* 检查规则对应卡券核销总数量上限 */
        if (CommonConstant.ZERO <= totalQtyAcc.compareTo(quantity)) {
            rglog.info("当前历史累计核销卡券数量<{}>已超过规则<{}>对应的最大可核销数量<{}>,不予优惠!",
                    mcTotalQtyAcc.toString(), ruleIndex, quantity.toString());
            return CommonConstant.PROCESS_FAILED;
        }
        /* 检查单日卡券核销数量上限 */
        if (CommonConstant.ZERO <= dayTotalQtyAcc.compareTo(dayRedeemLimit)) {
            rglog.info("当前当日累计核销卡券数量<{}>已超过规则<{}>对应的当日最大可核销数量<{}>,不予优惠!",
                    dayTotalQtyAcc.toString(), ruleIndex, dayRedeemLimit.toString());
            return CommonConstant.PROCESS_FAILED;
        }
        /* 如果是银商联合的活动  判断是否超出商户最大优惠金额 */
        if (CommonConstant.SPONSOR_MIXED.equals(mcCouponTxnData.getSponsor())) {
            //银行出资比例
            String bankBudgetRatio = mcCouponTxnData.getBankBudgetRatio();
            //本次银行补贴金额
            String bankSubsidy = new BigDecimal(mcCouponTxnData.getCouponAmt()).multiply(new BigDecimal(bankBudgetRatio)).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP).toString();
            //本次商户补贴金额
            String mchntSubsidy = new BigDecimal(mcCouponTxnData.getCouponAmt()).subtract(new BigDecimal(bankSubsidy)).toString();
            //银行出资金额
            String bankBudget = new BigDecimal(budget).multiply(new BigDecimal(bankBudgetRatio)).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP).toString();
            //商户出资金额
            String mchntBudget = new BigDecimal(budget).subtract(new BigDecimal(bankBudget)).toString();
            //预期参与商户数量
            String expectMchntQty = mcCouponTxnData.getExpectMchntQty();
            /* 每商户最大优惠金额 */
            BigDecimal mchntDiscountLimitAmt = (new BigDecimal(budget).subtract(new BigDecimal(bankBudget))).divide(new BigDecimal(expectMchntQty), CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户历史累计优惠金额 */
            BigDecimal mchntTotalAmtAcc = new BigDecimal(mcCouponTxnData.getMchntTotalAmtAcc()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户当日累计优惠金额 */
            BigDecimal mchntDayTotalAmtAcc = new BigDecimal(mcCouponTxnData.getMchntDayTotalAmtAcc()).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);
            /* 商户截止到当前交易前累计优惠金额 */
            BigDecimal mchntCurrentTotalAmtAcc = mchntTotalAmtAcc.add(mchntDayTotalAmtAcc).setScale(CommonConstant.DECIMAL_SCALE_TWO, RoundingMode.HALF_UP);

            /* 联合营销判断商户剩余可优惠额度 */
            if (CommonConstant.ZERO < mchntCurrentTotalAmtAcc.compareTo(mchntDiscountLimitAmt)) {
                /* 若当前商户累计交易金额大于商户最大优惠金额,流程结束,不予优惠 */
                rglog.info("当前商户累计优惠金额<{}>已超过商户最大优惠金额<{}>,不予优惠!", mchntCurrentTotalAmtAcc.toString(), mchntDiscountLimitAmt.toString());
                return CommonConstant.PROCESS_FAILED;
            } else {
                /* 若当前商户累计交易金额不大于商户最大优惠金额,但当前商户累计交易金额加本笔交易计算的优惠额大于商户最大优惠金额,则不予优惠 */
                if (CommonConstant.ZERO < mchntCurrentTotalAmtAcc.add(new BigDecimal(mchntSubsidy)).compareTo(mchntDiscountLimitAmt)) {
                    rglog.info("当前商户累计优惠金额<{}>已超过商户最大优惠金额<{}>,不予优惠!", mchntCurrentTotalAmtAcc.add(new BigDecimal(mchntSubsidy)).toString(), mchntDiscountLimitAmt.toString());
                    return CommonConstant.PROCESS_FAILED;
                }
            }
        }

        /* 本类营销活动预算是固定的,后面添加金额校验,目前暂不校验 */

        return CommonConstant.PROCESS_SUCCESS;
    }

    /**
     * 获取上送userId的参与优惠次数
     *
     * @throws Exception 异常信息
     * @author liujinan
     * @since 2020/11/13 23:40
     */
    private int selectUserIdTotalQtyAcc(String mcNo, TMStat2CUserDayTransCount tmStat2CUserDayTransCount) throws Exception {
        String userId = tmStat2CUserDayTransCount.getUserId();
        String mcType = tmStat2CUserDayTransCount.getMcType();
        String mcStartDate = tmStat2CUserDayTransCount.getMcStartDate();
        String lastDate = DateUtil.getBaseDateOffsetDay(globalTxnDate, CommonConstant.MINUS_ONE);
        int todayQtyAcc = tmStat2CUserDayTransCount.getDayPaymentCount();
        rglog.info("卡号<{}> 营销活动<{}>该卡号当日已参加此活动次数<{}>", userId, mcNo, todayQtyAcc);

        //获取对客营销活动用户统计表数据
        TMStat2CUser tmStat2CUser = getToClientMcUserStatistics(mcNo, userId, mcType, mcStartDate);

        if (null == tmStat2CUser) {
            rglog.error("机构<{}> 对客营销活动<{}> 卡号<{}> 获取对客营销活动用户统计表数据异常，不可参与本活动!", globalInstId, mcNo, userId);
            return CommonConstant.MINUS_ONE;
        }

        //累计优惠笔数
        int totalQtyAcc = Integer.parseInt(tmStat2CUser.getTotalQtyAcc());

        //活动统计的加当日统计的正向交易减去当日退货
        totalQtyAcc = totalQtyAcc + todayQtyAcc - tmStat2CUserDayTransCount.getDayRefundCount();

        rglog.info("卡号<{}> 营销活动<{}>该卡号已参加此活动次数<{}>", userId, mcNo, totalQtyAcc);

        return totalQtyAcc;
    }

    /**
     * 使用主键查询统计信息备份表最新一条数据
     *
     * @param instId
     * @param statType
     * @param statPrimaryKey
     * @return cc.rengu.igas.momp.common.entity.TMStatMfdPeriod
     * @throws Exception
     * @author liujinan
     * @date 2021/7/9
     */
    private TMStatBak selectTMStatBakByStatPrimaryKey(String instId, String statType, String statPrimaryKey) throws Exception {

        TMStatBakMapper tmStatBakMapper = new TMStatBakMapperImpl();
        return tmStatBakMapper.selectTMStatBakByStatPrimaryKey(instId, statType, statPrimaryKey);
    }

    /**
     * 对客活动用户统计表赋值
     *
     * @param tmStat2CUser              对客活动统计表
     * @param tMStat2CUserDayTransCount 对客活动单日统计
     * @author liujinan
     * @since 2021/7/12 11:23
     */
    private void copytmStat2CUserData(TMStat2CUser tmStat2CUser, TMStat2CUserDayTransCount tMStat2CUserDayTransCount) {

        /* 对客活动统计表-累计优惠笔数 */
        tmStat2CUser.setTotalQtyAcc(new BigDecimal(tmStat2CUser.getTotalQtyAcc()).add(new BigDecimal(tMStat2CUserDayTransCount.getDayPaymentCount())).subtract(new BigDecimal(tMStat2CUserDayTransCount.getDayRefundCount())).toString());
    }

    /**
     * 对客活动用户月统计表数据赋值
     *
     * @param tmStat2CUserMonth         对客活动月统计表
     * @param tMStat2CUserDayTransCount 对客活动单日统计
     * @author liujinan
     * @since 2021/7/12 11:23
     */
    private void copytmStat2CUserMonthData(TMStat2CUserMonth tmStat2CUserMonth, TMStat2CUserDayTransCount tMStat2CUserDayTransCount) {

        /* 对客活动月统计表-累计优惠笔数 */
        tmStat2CUserMonth.setTotalQtyAcc(new BigDecimal(tmStat2CUserMonth.getTotalQtyAcc()).add(new BigDecimal(tMStat2CUserDayTransCount.getDayPaymentCount())).subtract(new BigDecimal(tMStat2CUserDayTransCount.getDayRefundCount())).toString());
    }

    /**
     * 对客活动统计表赋值
     *
     * @param tmStat2C    对客活动统计表
     * @param tmStat2CDay 对客活动单日统计
     * @author liujinan
     * @since 2021/7/12 11:23
     */
    private void copytmStat2CData(TMStat2C tmStat2C, TMStat2CDay tmStat2CDay) {

        /* 对客活动统计表-总预算累计消耗笔数 */
        tmStat2C.setTotalQtyAcc(new BigDecimal(tmStat2C.getTotalQtyAcc()).add(new BigDecimal(tmStat2CDay.getTotalQtyAcc())).toString());
        /* 对客活动统计表-总预算累计消耗金额 */
        tmStat2C.setTotalAmtAcc(new BigDecimal(tmStat2C.getTotalAmtAcc()).add(new BigDecimal(tmStat2CDay.getTotalAmtAcc())).toString());
    }

    /**
     * 对客活动统计表赋值
     *
     * @param tmStat2CMchnt    对客活动商户统计表
     * @param tmStat2CMchntDay 对客活动商户单日统计
     * @author liujinan
     * @since 2021/7/12 11:23
     */
    private void copytmStat2CMchntData(TMStat2CMchnt tmStat2CMchnt, TMStat2CMchntDay tmStat2CMchntDay) {

        /* 对客活动统计表-总预算累计消耗笔数 */
        tmStat2CMchnt.setTotalQtyAcc(new BigDecimal(tmStat2CMchnt.getTotalQtyAcc()).add(new BigDecimal(tmStat2CMchntDay.getTotalQtyAcc())).toString());
        /* 对客活动统计表-总预算累计消耗金额 */
        tmStat2CMchnt.setTotalAmtAcc(new BigDecimal(tmStat2CMchnt.getTotalAmtAcc()).add(new BigDecimal(tmStat2CMchntDay.getTotalAmtAcc())).toString());
    }
}
